2017-12-18 1 views
1

私はテストライブラリノード-ジャスミンして以下の機能をテストユニットにしようとしているとのユニットテスト:ユニットは、機能をテストするとき避け副作用ときジャスミン

joinGame(participant) { 
    console.log('Joining game', participant); 

    if (this.getParticipants().length >= MAX_NUMBER_OF_PARTICIPANTS) { 
     throw new Error(`The game with id ${this.getId()} has reached the maximum amount of participants, ${MAX_NUMBER_OF_PARTICIPANTS}`); 
    } 

    this.addParticipant(participant); 
    this.incrementPlayerCount(); 

    this.emit(actions.GAME_JOINED, participant); 

    // Is the game ready to start? 
    if (this.playerCount >= REQUIRED_NUMBER_OF_PARTICIPANTS) { 
     // Start game loop by initializing the first round 
     this.createRound(); 
    } 
} 

ただし、コードパスのカップルがつながります私は関数の最後にあるthis.createRound()を呼び出します。 createRound()は、基本的にゲームループ、開始タイマー、および私が単体テストしている関数とは全く関係のないその他の副作用を初期化します。以下のテストを見てください:

it('should throw an error if a user tries to join a game with the maximum amount of participants has been reached',() => { 
    game = new Game(); 

    // To test whenever there are two participants in the game 
    game.joinGame(hostParticipant); 
    game.joinGame(clientParticipant); 

    function testJoin() { 
     game.joinGame(joiningParticipant); 
    } 

    expect(testJoin).toThrow(); 
}); 

私がテストを実行すると、テストは私の意志に対して 'createRound()'を呼び出します。 'createRound()'はRoundインスタンスをインスタンス化し、カウントダウンタイマーを開始します。これにより、コマンドラインの 'npm test'コールは決して終了しません。テストはそれがテストの一部だと思うので。

以下は、私が考えて実装した多くのアプローチです。しかし、私はそれらのいずれかが "きれい"であるとは思わないが、そのためにあなたの意見を求めている。

アプローチ1:機能の代わりにテスト内にスタブ 'createRound()'を挿入します。これは正常に動作しますが、それは副作用を呼び出さないようにする正しい方法ですか?

アプローチ2: beforeEach/afterEachでゲームインスタンスを設定/解除してみてください。私はこのアプローチを成功させることを試みました。ただし、 'afterEach()'でゲームインスタンスをnullに設定すると、インスタンス化されたラウンドインスタンスはそのタイマーに沿って継続します。

アプローチ3: 'joinGame()'を呼び出してRoundインスタンスを提供するときは、依存関係注入を使用します。しかし、これはあまり意味がありません。なぜなら、 'joinGame()'を呼び出すときに、新しいラウンドインスタンスを提供するのはクライアントの責任であってはならないからです。さらに、 'joinGame()'へのすべての呼び出しが 'createRound()'を呼び出すわけではありません。プレイヤー数が必要なプレイヤー数を超えた場合に限ります。

答えて

2

スタブcreateRoundが当然です。タイマーが期待どおりに動作するかどうかではなく、ユーザーがフルゲームに参加することを拒否する動作をアサートするテストを作成しています。テスト中のオブジェクトのメソッドをスタブしている場合、これはちょっと毛深くなりますが、タイマーを管理するロジックはおそらくそれ自身の別のオブジェクトに属すると主張します。もちろん

は、あなたも考慮することができます。

アプローチ4:ジャスミンdocumentationで説明したように、クロックモック。タイマーがsetTimeout/setIntervalに依存していると仮定すると、ファンクションを呼び出す前に偽時計をインストールし、クロックを手動でチェックしてアサーションを行うことができる状態にすることができます。

関連する問題