4

私のアプリケーションでは、ユーザーは 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
      });
    });
  }());
4

3 に答える 3

6

バイナリ ファイルを 16 進文字列としてエンコードし、それを 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 アプリを作成して、ファイルの内容を 16 進数でエンコードされた文字列として出力し、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

追加の情報...正確な状況はわかりませんが、次のことをお勧めします...

いつでも新しいバイナリを追加してテストを再実行する必要がある場合は、ランダムに追加するバイナリ ファイルの種類ごとにテストを行う必要があります。肯定的なファイルと否定的なファイルの両方をテストします (つまり、アプリで動作するファイルと、アプリで動作しないファイル)。それが、単体テスト フレームワークの目的です。将来、コードのバグが原因でアプリを破損させるファイルが見つかった場合は、バグを修正し、新しい単体テストを追加してそのバイナリをロードすると、テストに合格するはずです。ある時点で誤ってファイル処理コードを壊してしまった場合、ユニット テストは常にそこにあり、何かが間違っていることを示します。

于 2013-04-26T15:10:27.807 に答える
2

バイナリファイルを提供するために、別のポートで追加の grunt サーバーを実行することを回避できると思います。カルマの最新バージョンでは、ファイルがどのように含まれ、カルマ サーバーによって提供されるかについて、いくつかの詳細を定義できます。したがって、ファイルにテスト データを含め、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/' で始まるパスを見つけます。Karma が何をしているのか 100% はわかりませんが、xhr.open パスのプレフィックスとして「/base/」を使用してみましたが、うまくいくようです :)

 var url = '/base/src/specs/data/MyInterface.class';
 xhr.open('GET', url, true); 

また、クライアントでバイナリ データ ファイルを読み取るプロジェクトに取り組んでおり、Karma を使用してテストを行っているので、インスピレーションを得るためにあなたの質問を読むことができてうれしかったです。Karma の新しい機能は、アプローチを簡素化するのに非常に役立ちます。

于 2013-09-02T18:55:08.463 に答える
2

grunt を使用してプロジェクトをビルドし、単体テストを実行します。以下は、、、grunt.jsおよびtestacular.conf.jsテスト ( javaclassstreamreader.spec.js) です。grunt-serverつまり、バイナリ データ ファイルを提供するように構成されたgrunt が起動します。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);
        });
      });

    });

  }());
于 2013-01-09T03:29:02.227 に答える