Как загрузить двоичный файл во время модульного теста javascript?
В моем приложении пользователь использует HTML5 drag and drop для обработки двоичного файла. Эта часть кода работает нормально. В 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
});
});
}());
3 ответа:
Я решил эту проблему, закодировав двоичный файл в виде шестнадцатеричной строки, вставив его в большой двоичный объект и вызвав функцию, которая принимает объект 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); });
Функция в классе загрузчика файлов выглядит примерно так (в 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. (К вашему сведению, это мой первый скрипт на python примерно за 12 лет, я уверен, что он не эффективен, но он был быстрым) большое спасибо коллеге за выходную строку. Я не знаю, почему кодовый блок вырезается на дисплее. Мое извинение.
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
используется для извлечения двоичного файла. Все работает, но кажется немного сложным. Есть ли более простой способ?Ворчание.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'); };
Тестакулярный.конф.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.спекуляция.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. Таким образом, вы бы включили свои тестовые данные в файлы и сказали бы Карме служить, но не смотреть или включать эти файлы
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.откройте ('GET',") и сбросьте responseText, вы получите вывод со всеми включенными скриптами / файлами, передаваемыми в Karma, и там вы найдете пути, которые начинаются с '/base/' и иногда '/absolute/'. Не уверен на 100% , что делает карма, но я попробовал использовать '/base/' в качестве префикса для xhr.откройте путь, и это, кажется, работает:)
var url = '/base/src/specs/data/MyInterface.class'; xhr.open('GET', url, true);
Я также работаю над проектом, который включает в себя чтение двоичных файлов данных в клиенте, а также работу с кармой для тестирования, так что это было здорово прочитать ваш вопрос для вдохновения. В конце концов я обнаружил, что новая функциональность в Karma действительно полезна для упрощения подхода!