如何在javascript单元测试期间加载二进制文件?

如何在javascript单元测试期间加载二进制文件?,javascript,jasmine,arraybuffer,karma-runner,Javascript,Jasmine,Arraybuffer,Karma Runner,在我的应用程序中,用户使用HTML5拖放来处理二进制文件。代码的这一部分工作正常。在chrome中,我拖动一个二进制文件并使用文件读取器创建arrayBuffer。这一切似乎都很好。我正在为这个功能编写测试,我感到不知所措。如何将二进制文件加载到单元测试中?对于我正在测试的代码,我只需要一个arrayBuffer。目前,我正在手动创建arrayBuffer,但这不是一个可持续的解决方案。为了使我的测试有效,我需要能够随时抛出一个新的二进制文件并进行新的测试。我的测试环境是TestCular+ja

在我的应用程序中,用户使用HTML5拖放来处理二进制文件。代码的这一部分工作正常。在chrome中,我拖动一个二进制文件并使用文件读取器创建arrayBuffer。这一切似乎都很好。我正在为这个功能编写测试,我感到不知所措。如何将二进制文件加载到单元测试中?对于我正在测试的代码,我只需要一个arrayBuffer。目前,我正在手动创建arrayBuffer,但这不是一个可持续的解决方案。为了使我的测试有效,我需要能够随时抛出一个新的二进制文件并进行新的测试。我的测试环境是TestCular+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
      });
    });
  }());

我使用grunt构建项目并运行单元测试。下面是我的
grunt.js
testacular.conf.js
,以及测试(
javaclassstreamreader.spec.js
)。简而言之,grunt启动
grunt服务器
,该服务器被配置为提供二进制数据文件。TestCular配置为代理
grunt服务器
。在测试中,
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');
};
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);
        });
      });

    });

  }());

通过将二进制文件编码为十六进制字符串,将其填充到blob中,并调用获取file对象的函数,我解决了这个问题。我用Jasmine来测试一个文件加载函数。FileLoader是我编写的具有函数loadFromFile的类

文件加载器类中的函数类似于(在coffeescript中)。您应该明确地将错误处理添加到您的商业代码中

我编写了以下小型python应用程序,将文件内容作为十六进制编码字符串输出,该字符串可以用作javascript字符串的内容。(仅供参考,这是我12年来的第一个python脚本,我相信它效率不高,但速度很快)多亏了一位同事的输出字符串。我不知道为什么代码块会在显示屏上被破坏。我道歉

其他花絮。。。我不知道你的具体情况,但我建议如下


如果您需要随时添加新的二进制文件并重新运行测试,那么您应该对随机添加的每种二进制文件进行测试。测试正文件和负文件(即应与应用程序一起使用的文件,不应与应用程序一起使用的文件)。这就是单元测试框架的用途。将来,如果您发现某个文件由于代码中的错误而破坏了您的应用程序,您可以修复该错误,添加新的单元测试以加载该二进制文件,然后测试应该通过。如果您碰巧在某个时候意外地破坏了文件处理代码,那么单元测试总是会向您显示出一些错误。

我认为您可以在不同的端口上运行额外的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.open方法中。如果您将一个空字符串传入xhr.open('GET',''),并转储responseText,您将得到一个输出,其中所有包含的脚本/文件都将传递给Karma,在那里,您将找到以“/base/”开头的路径,有时还以“/absolute/”开头的路径。100%不确定Karma在做什么,但我尝试使用“/base/”作为xhr.open路径的前缀,它似乎有效:)


我也在做一个项目,涉及读取客户机中的二进制数据文件,并与Karma一起进行测试,因此阅读您的问题以获得灵感非常好。我最终发现Karma中的新功能在简化方法方面非常有用

我第一次开始时也做了类似的事情,但我不喜欢每次想测试时都要转换文件。但是,安装比使用web服务器更简单,因此我感谢您添加一个替代方案。您的解决方案似乎对小型二进制数据集非常有效,但我需要加载更大的文件。
  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);
  });
  #
  # 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
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
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'
];
 var url = '/base/src/specs/data/MyInterface.class';
 xhr.open('GET', url, true);