【问题标题】:Avoid side effect when unit testing with Jasmine使用 Jasmine 进行单元测试时避免副作用
【发布时间】:2018-06-01 01:15:44
【问题描述】:

我正在尝试使用测试库 node-jasmine 对以下函数进行单元测试:

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 上设置/拆除 Game 实例。我试过这种方法没有成功。但是,通过在 'afterEach()' 上将游戏实例设置为 null,实例化的回合实例会继续与其计时器一起运行。

方法 3: 在调用 'joinGame()' 并提供 Round 实例时使用依赖注入。但这并没有多大意义,因为在调用“joinGame()”时提供一个新的回合实例不应该是客户的责任。此外,并非每次调用“joinGame()”都会调用“createRound()”;仅当玩家人数超过所需玩家人数时。

【问题讨论】:

    标签: node.js unit-testing jasmine


    【解决方案1】:

    存根createRound 当然是有道理的。您正在编写一个测试来断言拒绝用户加入完整游戏的行为,而不是计时器是否按预期工作。如果您在被测对象上存根方法,这会有点麻烦,但是我会争辩说,管理计时器的逻辑可能属于它自己的单独对象。

    当然,你也可以考虑:

    方法 4: 模拟 jasmine documentation 中描述的时钟。假设计时器依赖于setTimeout/setInterval,您可以在调用该函数之前安装假时钟,并手动勾选时钟以获取可以进行断言的状态。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-14
      • 2015-09-01
      • 2014-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多