非同期関数を呼び出している間のモカテストで、タイムアウトエラーを回避する方法:タイムアウトが2000msを超えました


200

私のノードアプリケーションでは、モカを使用してコードをテストしています。mochaを使用して多くの非同期関数を呼び出しているときに、タイムアウトエラー(Error: timeout of 2000ms exceeded.)が発生します。どうすればこれを解決できますか?

var module = require('../lib/myModule');
var should = require('chai').should();

describe('Testing Module', function() {

    it('Save Data', function(done) {

        this.timeout(15000);

        var data = {
            a: 'aa',
            b: 'bb'
        };

        module.save(data, function(err, res) {
            should.not.exist(err);
            done();
        });

    });


    it('Get Data By Id', function(done) {

        var id = "28ca9";

        module.get(id, function(err, res) {

            console.log(res);
            should.not.exist(err);
            done();
        });

    });

});

統合テストですか?テストを実行するには時間がかかります-おそらくスタブを検討する必要があります-github.com/thlorenz/proxyquireが役立つかもしれません。
スルイ2013年

@suruiは、私はそれになりますありがとう
サチン

非同期のものにプロミスを使用してそれをテストすることをお勧めします。そうすれば、チャイをプロミスとして
Krym '19

回答:


344

テストを実行するときにタイムアウトを設定できます。

mocha --timeout 15000

または、プログラムで各スイートまたは各テストのタイムアウトを設定できます。

describe('...', function(){
  this.timeout(15000);

  it('...', function(done){
    this.timeout(15000);
    setTimeout(done, 15000);
  });
});

詳細については、ドキュメントを参照してください。


3
短いバージョンは-tです。mocha-testを使用してgruntタスクからmochaを実行する場合、これはオプションオブジェクトでもサポートされますoptions:{timeout:15000}
svassr 2014

5
参考:アロー関数をMochaに渡すことはお勧めしません。mochajs.org/#arrow-functions
2017年

4
上記のリンクでは、矢印関数は推奨されていません。コンテキストにアクセスする必要があるときに失敗しないように、それらが何をするかを知る必要があるだけです。タイムアウトに依存するのは壊れやすく、すべてのテストは数ミリ秒で実行されるため、コンテキストは必要ありませんが、sinon-testを使用すると同じ問題が発生します。それでも99%はラムダを使用します。
オリゴフレン2017年

26
TypeError: this.timeout is not a function使用時"mocha": "^3.5.0"
JuniorMayhéSep

5
@adi、アロー関数を使用していないのですか?async / awaitに関してはドキュメントにあるので動作するはずです(そしてpromiseを使用するのと同じです)。別の質問のように聞こえますが。
Andreas Hultgren

80

タイムアウトを増やすだけの「解決策」は、ここで実際に起こっていることを覆い隠していることがわかります。

  1. コードやネットワークの呼び出しが遅すぎる(ユーザーエクスペリエンスを向上させるには100ミリ秒未満である必要があります)
  2. アサーション(テスト)が失敗し、Mochaがアサーションを実行する前に何かがエラーを飲み込んでいます。

通常、Mochaがコールバックからアサーションエラーを受信しない場合、#2が発生します。これは、スタックのさらに上位で例外を飲み込む他のコードが原因です。これに対処する正しい方法は、コードを修正してエラーを飲み込まないことですです。

外部コードがエラーを飲み込んだとき

変更できないライブラリ関数の場合は、アサーションエラーをキャッチして自分でMochaに渡す必要があります。これを行うには、アサーションコールバックをtry / catchブロックでラップし、すべての例外をdoneハンドラーに渡します。

it('should not fail', function (done) { // Pass reference here!

  i_swallow_errors(function (err, result) {
    try { // boilerplate to be able to get the assert failures
      assert.ok(true);
      assert.equal(result, 'bar');
      done();
    } catch (error) {
      done(error);
    }
  });
});

もちろん、このボイラープレートをいくつかのユーティリティ関数に抽出して、テストをもう少し見やすくすることができます。

it('should not fail', function (done) { // Pass reference here!
    i_swallow_errors(handleError(done, function (err, result) {
        assert.equal(result, 'bar');
    }));
});

// reusable boilerplate to be able to get the assert failures
function handleError(done, fn) {
    try { 
        fn();
        done();
    } catch (error) {
        done(error);
    }
}

ネットワークテストの高速化

それ以外は、機能しているネットワークに依存せずにテストに合格するために、ネットワーク呼び出しにテストスタブを使い始める際のアドバイスを参考にしてください。モカ、チャイ、シノンを使用すると、テストは次のようになります。

describe('api tests normally involving network calls', function() {

    beforeEach: function () {
        this.xhr = sinon.useFakeXMLHttpRequest();
        var requests = this.requests = [];

        this.xhr.onCreate = function (xhr) {
            requests.push(xhr);
        };
    },

    afterEach: function () {
        this.xhr.restore();
    }


    it("should fetch comments from server", function () {
        var callback = sinon.spy();
        myLib.getCommentsFor("/some/article", callback);
        assertEquals(1, this.requests.length);

        this.requests[0].respond(200, { "Content-Type": "application/json" },
                                 '[{ "id": 12, "comment": "Hey there" }]');
        expect(callback.calledWith([{ id: 12, comment: "Hey there" }])).to.be.true;
    });

});

詳細については、Sinonのniseドキュメントを参照してください。


私は巨大な一連のテストを行っており、仕様のすべてのプロミスを確認して、すべてがプロミスdone()の最後に呼び出されていることを確認しました$httpBackend。また、Angularを使用してネットワークコールを模倣していますが、運はありません。すべてのスペックをtry-catchでラップするのは、あまり実用的ではないようです。他に何か提案はありますか?ありがとう!
Gustavo Matias

@GustavoMatiasあなたは実際にあなたの問題が何であるかについて言及していません、これはあなたが問題を抱えているものに対する解決策ではないことを述べました。詳細な説明をしてください:-)テストが十分に速く失敗しませんか?彼らは時々失敗していますが、なぜ知りたいですか?あなたが達成しようとしていることを推測するのは難しい。
オリゴフレン2016年

こんにちは@oligofren!それは確かに最良の説明ではありませんでした。ここに私の問題のより詳細な説明があります。stackoverflow.com/ questions / 34510048 / …ありがとう!
Gustavo Matias

「一般的に、この問題を処理する最もクリーンな方法(ただし、醜い方法)は、コードをtry / catchでラップし、例外をdoneハンドラーに渡すことです。」いいえ、これはまったくクリーンな方法ではありません。ロングショットではありません。最もきれいな方法は、例外を飲み込まないコードを書くことです。モカが失敗したテストを検出していないと誰かが不平を言うのを見るたびに、それは例外を飲み込む何かがあったからでした。テスト中のコードのバグを修正するのではなく、回避するためのtry.... catch...機能を追加します。
Louis

@Louisあなたはここで理由についておそらく正しいかもしれませんが、私はそれをすぐに確認することはできません。とにかく、人々はモカがいくつかのエラーを捕まえることができないように見えるという問題を抱えています、そしてこれはそれを処理する方法です。あなたの与えられたアプローチは、エラーを飲み込むコードがいくつかのライブラリ関数または類似のものではないことを想定しています。その場合、それはそれほど簡単に解決されないでしょう。
オリゴフレン

7

少し遅れますが、将来的に誰かがこれを使用できるようになります... package.jsonのスクリプトを次のように更新することで、テストのタイムアウトを増やすことができます。

"scripts": { "test": "test --timeout 10000" //Adjust to a value you need }

コマンドを使用してテストを実行します test


私のために働いた!ありがとうございます!
RayLoveless

5

矢印関数を使用している場合:

it('should do something', async () => {
  // do your testing
}).timeout(15000)

1

私にとって問題は、実際には記述関数でした。これは、矢印関数が提供されると、mochaがタイムアウトを見逃し、一貫して動作しない原因になります。(ES6を使用)

拒否された約束がないため、describeブロック内で失敗したさまざまなテストで常にこのエラーが発生していました

だから、これは正しく機能していないときの見え方です:

describe('test', () => { 
 assert(...)
})

これは無名関数を使用して機能します

describe('test', function() { 
 assert(...)
})

上記の私の設定が誰かを助けることを願っています:(nodejs:8.4.0、npm:5.3.0、mocha:3.3.0)


0

私の問題は応答を返送することではなかったため、ハングしていました。expressを使用している場合は、res.send(data)、res.json(data)または使用するAPIメソッドが、テストするルートに対して実行されることを確認してください。


0

テストケースで使用されているpromiseを解決または拒否します。スパイやスタブが解決または拒否することを確認してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.