0

申し訳ありませんが、ノードから始めてください。これは非常に初歩的な質問かもしれません。

ファイルシステムのディレクトリからいくつかのファイルを読み取るコードがあるとしましょう:

var fs = require('fs');

fs.readdir(__dirname + '/myfiles', function (err, files) {
    if (err) throw err;
    files.forEach(function (fileName) {
        fs.readFile(__dirname + '/myfiles/' + fileName, function (err, data) {
            if (err) throw err;
            console.log('finished reading file ' + fileName + ': ' + data);
            module.exports.files.push(data);
        });
    });
});

これはすべて非同期で行われることに注意してください。また、次のコードを実行する Mocha テストがあるとします。

describe('fileProvider', function () {
    describe('#files', function () {
        it.only('files array not empty', function () {
            assert(fileProvider.files.length > 0, 'files.length is zero');
        });
    });
});

mocha テストは、ファイルの読み取りが完了する前に実行されます。これは、mocha テストが実行されていることを示す小さなドットが表示された後に console.log ステートメントが表示されるためです (少なくとも、それが示されていると思います)。また、アサートを setTimeout で囲むと、アサートはパスします。

非同期ファイル操作が確実に完了するようにするには、コードをどのように構成すればよいですか? これはテストの問題だけではないことに注意してください。アプリで実際の作業を行う前に、ファイルを完全にロードする必要があります。

ファイルを同期的に読み取ることが正しい答えだとは思いません。ノードの要求/応答ループがブロックされるからですよね?

おまけの質問:
タイムアウト値が 0 の setTimeout にアサートを入れても、テストは成功します。これは、 setTimeout に入れるだけで、処理チェーンの最後までキックするか、ファイルシステムの作業が最初に終了するためですか?

4

3 に答える 3

0

これは良いテストだと思います。モジュールを使用するアプリでも同じことが起こります。つまり、files設定する前にコードを実行できます。あなたがする必要があるのは、@ Making3 が提案するようなコールバックを作成するか、promise を使用することです。私はモカを使用していませんが、非同期呼び出しに関するセクションがあります。promise 自体をエクスポートできます。

module.exports.getFiles = new Promise((resolve, reject) => {
  datas = [];
  fs.readdir(__dirname + '/myfiles', function (err, files) {
      if (err) {
        reject(err);
        return;
      }
      files.forEach(function (fileName) {
          fs.readFile(__dirname + '/myfiles/' + fileName, function (err, data) {
              if (err) {
                reject(err);
                return;
              }
              console.log('finished reading file ' + fileName + ': ' + data);
              datas.push(data);
              if (datas.length == files.length) {
                resolve(datas);
              }
          });
      });
  });
}

chai-as-promissedを使用すると、を使用して promiseを直接操作できますeventually。または、テストに渡されたコールバックを使用することもできます。

describe('fileProvider', function () {
    describe('#files', function () {
        it.only('files array not empty', function (done) {
            fileProvider.getFiles.then(function(value) {
                assert(value.length > 0, 'files.length is zero');
                done();
            }, function(err) {
                done(err);
            })
        });
    });
});
于 2016-08-25T10:50:23.357 に答える