如何在javascript单元测试期间加载二进制文件?
How do I load a binary file during javascript unit test?
在我的应用程序中,用户使用HTML5拖放来处理二进制文件。这部分代码运行良好。在chrome中,我拖动一个二进制文件,并使用FileReader创建一个arrayBuffer。这一切似乎都很顺利。我正在为这个功能编写测试,我很困惑。如何将二进制文件加载到单元测试中?对于我正在测试的代码,我只需要一个arrayBuffer。目前,我正在手动创建arrayBuffer,但这不是一个可持续的解决方案。为了使我的测试有效,我需要能够在任何时候放入一个新的二进制文件并进行新的测试。我的测试环境是testacular+jasmine。
( function() {"use strict";
function loadSimpleDataView() {
//instead of defining ArrayBuffer,
//I want it to be generated based upon an external file
var buffer = new ArrayBuffer(4), dataView = new DataView(buffer), int8View = new Int8Array(buffer);
int8View.set([0x00,0x01,0x02,0x03]);
return dataView;
}
describe('mymodule', function() {
it('mytest', function() {
var dataView = loadSimpleDataView();
expect(dataView).toBeDefined();
//do rest of tests
});
});
}());
我通过将二进制文件编码为十六进制字符串,将其填充到blob中,并调用接受file对象的函数来解决这个问题。我正在使用Jasmine测试文件加载功能。FileLoader是我写的类,它有loadFromFile函数。
beforeEach(function() { return this.fileLoader = new FileLoader() }); it("can load this bin file safely", function() { var blob, fileContentsEncodedInHex; fileContentsEncodedInHex = ["'x45'x6e'x63'x6f'x64'x65'x49'x6e'x48'x65'x78'x42'x65'x63'x61'x75'x73'x65'x42'x69'x6e'x61'x72'x79'x46'x69'x6c'x65'x73'x43'x6f'x6e'x74'x61'x69'x6e'x55'x6e'x70'x72'x69'x6e'x74'x61'x62'x6c'x65'x43'x68'x61'x72'x61'x63'x74'x65'x72'x73"]; blob = new Blob(fileContentsEncodedInHex); this.fileLoader.loadFromFile(blob); });
File loader类中的函数看起来像这样(在coffeescript中)。你绝对应该在你的商业代码中添加错误处理…
# # Load the file # # @param [File] file # The DOM file object # loadFromFile: (file) -> # create the file reader # assign the file load handler # read the array as a buffer, which will trigger the handler reader = new FileReader() reader.onloadend = this._handleOnLoadEnd reader.readAsArrayBuffer(file) return
我写了下面的小python应用程序来输出文件内容作为十六进制编码的字符串,可以用作javascript字符串的内容。(仅供参考,这是我大约12年来的第一个python脚本,我确信它效率不高,但它很快)非常感谢同事的输出字符串。我不知道为什么代码块在显示中被破坏了。我的歉意。
import sys fulldoc = "" with open('your file', 'rb') as readFile: while 1: character = readFile.read(1) if not character: break fulldoc = fulldoc + "''x" + character.encode("hex") print fulldoc
额外的花絮……我不知道你的具体情况,但我建议如下…
如果您需要随时添加新的二进制文件并重新运行测试,那么您应该对随机添加的每种二进制文件进行测试。测试正面和负面文件(即,应该与应用一起工作的文件,不应该与应用一起工作的文件)。这就是单元测试框架的作用。在未来,如果你发现一个文件因为代码中的错误而导致应用程序崩溃,你可以修复这个错误,添加一个新的单元测试来加载这个二进制文件,然后测试就会通过。如果您碰巧在某个时候意外地破坏了文件处理代码,单元测试总是在那里告诉您哪里出错了。
我使用grunt来构建项目并运行单元测试。下面是我的grunt.js
, testacular.conf.js
和测试(javaclassstreamreader.spec.js
)。简而言之,grunt启动配置为提供二进制数据文件的grunt-server
。Testacular被配置为代理grunt-server
。在测试中,XMLHttpRequest
用于检索二进制文件。一切都可以工作,但似乎有点复杂。有更简单的方法吗?
grunt.js:
/*global module:false*/
module.exports = function(grunt) {"use strict";
// Project configuration.
grunt.initConfig({
pkg : '<json:package.json>',
meta : {
banner : '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %>'n' + '<%= pkg.homepage ? "* " + pkg.homepage + "'n" : "" %>' + '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' + ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
},
lint : {
files : ['grunt.js', 'src/*.js', 'src/public/js/**/*.js', 'src/specs/**/*.js']
},
watch : {
files : '<config:lint.files>',
tasks : 'default'
},
exec : {
ensure_generated_directory : {
command : 'mkdir -p generated/js/'
}
},
clean : {
all : ['generated']
},
jshint : {
files : '<config:lint.files>',
options : {
curly : true,
eqeqeq : true,
forin : true,
immed : true,
latedef : true,
newcap : true,
noarg : true,
sub : true,
undef : true,
unused : true,
strict : true,
boss : true,
eqnull : true,
es5 : true,
browser : true,
jquery : true,
devel : true
},
globals : {
//jasmine
describe : false,
it : false,
expect : false,
//commonjs
require : false,
exports : true,
//angular
angular : false
}
},
'closure-compiler' : {
frontend : {
closurePath : 'closure-compiler',
js : ['src/*.js', 'src/public/js/**/*.js'],
jsOutputFile : 'generated/js/complete-app.js',
options : {
externs : 'externs.js',
compilation_level : 'SIMPLE_OPTIMIZATIONS',
language_in : 'ECMASCRIPT5_STRICT',
logging_level : 'ALL',
debug : null,
warning_level : 'verbose',
summary_detail_level : 3,
formatting : ['PRETTY_PRINT', 'PRINT_INPUT_DELIMITER'],
common_js_entry_module : 'src/public/js/app.js',
process_common_js_modules : null,
process_jquery_primitives : null,
common_js_module_path_prefix : 'src'
}
}
},
testacularServer : {
integration : {
options : {
keepalive : true
},
configFile : 'testacular.conf.js',
autoWatch : false,
singleRun : true
}
},
server : {
port : 18081,
base : './src/specs/data'
}
});
// Default task.
grunt.registerTask('default', 'lint exec:ensure_generated_directory closure-compiler server testacularServer:integration');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-closure-compiler');
grunt.loadNpmTasks('grunt-exec');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-testacular');
};
testacular.conf.js:
// Testacular configuration
// Generated on Tue Jan 01 2013 03:17:01 GMT-0500 (EST)
/*global basePath:true */
/*global files:true */
/*global JASMINE:false */
/*global JASMINE_ADAPTER:false */
/*global exclude:true */
/*global reporters:true */
/*global port:true */
/*global runnerPort:true */
/*global colors:true */
/*global logLevel:true */
/*global LOG_INFO:false */
/*global autoWatch:true */
/*global browsers:true */
/*global captureTimeout:true */
/*global singleRun:true */
// base path, that will be used to resolve files and exclude
basePath = '.';
// list of files / patterns to load in the browser
files = [
JASMINE,
JASMINE_ADAPTER,
'src/public/lib/jquery/1.7.2/jquery-1.7.2.min.js',
'src/public/lib/jquery-ui/1.8.20.custom/jquery-ui-1.8.20.custom.min.js',
'src/public/lib/angular/1.0.1/angular-1.0.1.min.js',
'src/public/lib/filer.min.js',
'generated/js/complete-app.js',
'src/specs/**/*.spec.js'
];
// list of files to exclude
exclude = [
];
// test results reporter to use
// possible values: 'dots', 'progress', 'junit'
reporters = ['progress'];
// web server port
port = 18080;
// cli runner port
runnerPort = 9100;
//proxy
proxies = {
'/test-data/': 'http://localhost:18081/'
};
// enable / disable colors in the output (reporters and logs)
colors = true;
// level of logging
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
logLevel = LOG_INFO;
// enable / disable watching file and executing tests whenever any file changes
autoWatch = true;
// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers = ['Chrome'];
// If browser does not capture in given timeout [ms], kill it
captureTimeout = 5000;
// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun = false;
javaclassstreamreader.spec.js:
/*global module$javaclassstreamreader:false */
/*global waitsFor:false */
/*global runs:false */
/*global dump:false */
( function() {"use strict";
var JavaClassStreamReader = module$javaclassstreamreader.JavaClassStreamReader;
function loadSimpleDataView(callback) {
var dataView;
var xhr = new XMLHttpRequest();
xhr.open('GET', '/test-data/MyInterface.class', true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
dataView = new DataView(this.response);
callback(dataView);
};
xhr.onerror = dump;
xhr.send();
}
describe('javaclassstreamreader', function() {
it('reader can be constructed', function() {
var hasData = false,reader;
loadSimpleDataView(function(dataView) {
reader = new JavaClassStreamReader(dataView);
hasData = true;
});
waitsFor(function() {
return hasData;
}, "Never retrieved file", 3000);
runs(function() {
expect(reader.offset).toBe(0);
var firstBytes = reader.getU4();
dump(firstBytes.toString(16));
expect(firstBytes).toBe(0xcafebabe);
expect(reader.maxOffset).toBe(126);
});
});
});
}());
我认为您可以绕过在不同端口上运行额外的grunt服务器来提供二进制文件。在最新版本的karma中,您可以定义有关如何包含文件并由karma服务器提供服务的一些细节。因此,您将在文件中包含测试数据,并告诉Karma提供服务,但不查看或包含这些文件
files = [
JASMINE,
JASMINE_ADAPTER,
'src/public/lib/jquery/1.7.2/jquery-1.7.2.min.js',
'src/public/lib/jquery-ui/1.8.20.custom/jquery-ui-1.8.20.custom.min.js',
'src/public/lib/angular/1.0.1/angular-1.0.1.min.js',
'src/public/lib/filer.min.js',
/* NEW LINE NEEDED BELOW! */
{pattern: 'src/specs/data/**', watched: false, included: false, served: true},
'generated/js/complete-app.js',
'src/specs/**/*.spec.js'
];
然后在您的测试中,您需要在xhr中获得文件的正确位置。开放的方法。如果您将一个空字符串传入xhr.open('GET', "),并转储responseText,那么您将得到一个输出,其中包含传递给Karma的所有脚本/文件,并且在那里,您将找到以'/base/'开头的路径,有时还会找到'/absolute/'。不确定100% Karma在做什么,但我尝试使用'/base/'作为xhr的前缀。打开路径,它似乎工作:)
var url = '/base/src/specs/data/MyInterface.class';
xhr.open('GET', url, true);
我也在做一个项目,包括在客户端读取二进制数据文件,并与Karma一起进行测试,所以很高兴能读到你的问题以获得灵感。我最终发现Karma中的新功能在简化方法方面非常有用!
- 什么更好?使用iframe或jQuery之类的东西在外部网站中加载HTML文件
- 在Javascript中加载JSON文件
- 如何在dojo应用程序构建概要文件中加载json文件
- 如何在three.js中加载指定文件内容而非路径的三维模型
- 使用ajax在html中加载html文件时出现的问题
- 加载Js文件应用程序加载
- 先在Angular中加载配置文件,然后再加载其他文件
- 没有在django项目中加载CSS文件
- 如何加载js文件并在CEF上执行
- 寻找HTML5视频是否需要加载整个文件
- 如何使用javascript只加载mp3文件标题
- 无法查找元素'手动加载CSS文件时的CSS属性
- IE7 未加载 JavaScript 文件
- 加载 js 文件时出现 404 错误
- 加载CSS文件并覆盖上一个文件
- Angular $http 服务不加载 json 文件
- 无法在 jsTree 中通过 HTTP 加载 XML 文件
- 使用 JavaScript 动态加载 CSS 文件
- 如何在打开模型时动态加载控制器文件
- 如何在javascript单元测试期间加载二进制文件?