如果给出来自服务器的响应,如何使测试失败?

How to fail test if response from server is given?

我正在开发一个 socket.io IRC,我不希望用户的用户名太长。我编写了以下 (mocha) 测试来验证在提供更长的用户名时服务器不会向每个连接的套接字发送响应:

  it("should not accept usernames longer than 15 chars", function (done) {
    var username = "a".repeat(server.getMaxUsernameLength() + 1);
    client1.emit("username change", username);
    client2.on("chat message", function (data) {
      throw Error("Fail, server did send a response.");
    });
    setTimeout(function () {
      done();
    }, 50);
  });

这目前确实有效,但远非最佳。如果我的 CI 平台速度较慢或服务器在超过 50 毫秒后没有响应怎么办?给出响应时使测试失败的最佳方法是什么,或者我应该以不同的方式构建我的测试?

谢谢!

P.s。这个问题与 Testing asynchronous function with mocha 不同,因为虽然问题确实与异步测试有关,但我知道 done() 方法(而且我显然正在使用它)。

您要做的是验证 client2.on("chat message"... 的回调从未被调用过。测试负面案例可能很困难,而且您正在尝试进行完整的端到端(客户端到服务器到客户端)集成测试这一事实似乎加剧了您的案例。就个人而言,我会尝试在单元案例套件中对此进行测试,并避免将异步性的复杂性引入测试。

但是,如果必须这样做,请参考 Eradicating Non-Determinism in Tests 的提示:

This is the trickiest case since you can test for your expected response, but there's nothing to do to detect a failure other than timing-out. If the provider is something you're building you can handle this by ensuring the provider implements some way of indicating that it's done - essentially some form of callback. Even if only the testing code uses it, it's worth it - although often you'll find this kind of functionality is valuable for other purposes too.

您的服务器应该向 client1 发送某种通知,它会忽略名称更改,即使您没有进行测试,但既然您正在测试,您可以使用这样的通知来验证它真的没有向其他客户发送通知。所以像:

it("should not accept usernames longer than 15 chars", function (done) {
  var chatSpy = sinon.spy();
  client2.on("chat message", chatSpy);
  client1.on('error', function(err) {
    assertEquals(err.msg, 'Username too long');
    assert(chatSpy.neverCalledWith(...));
    done();
  });

  var username = "a".repeat(server.getMaxUsernameLength() + 1);
  client1.emit("username change", username);
});

会合适。

此外,如果出于某种原因,server.getMaxUsernameLength() 曾经开始返回 15 以外的内容,最好的情况是您的测试描述变得错误。如果 getMaxUsernameLength 和处理名称更改事件的服务器代码不从同一个地方获取它们的值,情况会变得更糟。测试可能不应该依赖被测系统提供测试值。