使用mocha测试express服务器,使用异步初始化器测试supertest两次调用请求



我正在尝试为express服务器设置一个测试框架,而使用require异步初始化的测试给我带来了问题。起初,我尝试使用磁带和超级测试,但由于磁带似乎对异步操作的总体支持很差,所以我改用mocha。现在我至少收到了一些错误消息,但测试仍然不起作用。

我正在尝试测试一个伪ping端点/auth_ping,它应该需要一个有效的令牌来响应pong,否则应该响应403。目前身份验证还没有实现,所以我试图设置一个最初失败的测试,因为服务器在没有令牌的情况下请求时响应200而不是403。

我测试的第一次尝试看起来像这个

'use strict';
const request = require('supertest');
const app = require('../server');
const keycloak = require('./util/keycloak-mock');
describe("authenticated ping", function() {
it("should respond 403 when no token is provided", function(done) {
keycloak.fetchToken()
.then((token) => request(app)
.get("/auth_ping")
.expect(403)
.end(function (err, res) {
if (err) {
done(err)
};
done();
}));
});
});

测试用例从使用异步调用从模拟验证器获取有效令牌开始。在这个测试中,没有使用令牌,但我无论如何都想进行调用,以确保mock验证器已经初始化。无论如何,令牌都会在进一步的测试用例中使用,因此需要进行提取。

我使用这个测试得到的输出是以下

authenticated ping
Warning: superagent request was sent twice, because both .end() and .then() were called. Never call .end() if you use promises
Warning: .end() was called twice. This is not supported in superagent
superagent: double callback bug
(node:21) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected token { in JSON at position 29
at JSON.parse (<anonymous>)
at IncomingMessage.res.on (/usr/src/app/node_modules/superagent/lib/node/parsers/json.js:11:35)
at IncomingMessage.emit (events.js:203:15)
at endReadableNT (_stream_readable.js:1145:12)
at process._tickCallback (internal/process/next_tick.js:63:19)
(node:21) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:21) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
1) should respond 403 when no token is provided

0 passing (2s)
1 failing
1) authenticated ping
should respond 403 when no token is provided:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/usr/src/app/test/index.js)

我真的不确定这里的流程是如何工作的,也不知道为什么会发出两次请求。是的,我同时调用了then((和end((,但由于then(((与超级测试无关,我不知道它会如何影响请求。此外,end((似乎是我为mocha调用done((的唯一地方,所以我看不出没有它测试是如何工作的

无论如何,我试图通过删除end((调用来修改测试:

'use strict';
const request = require('supertest');
const app = require('../server');
const keycloak = require('./util/keycloak-mock');
describe("authenticated ping", function() {
it("should respond 403 when no token is provided", function(done) {
keycloak.fetchToken()
.then((token) => request(app)
.get("/auth_ping")
.expect(403)
);
});
});

之后的输出是:

authenticated ping
(node:21) UnhandledPromiseRejectionWarning: Error: expected 403 "Forbidden", got 200 "OK"
at Test._assertStatus (/usr/src/app/node_modules/supertest/lib/test.js:268:12)
at Test._assertFunction (/usr/src/app/node_modules/supertest/lib/test.js:283:11)
at Test.assert (/usr/src/app/node_modules/supertest/lib/test.js:173:18)
at Server.localAssert (/usr/src/app/node_modules/supertest/lib/test.js:131:12)
at Object.onceWrapper (events.js:286:20)
at Server.emit (events.js:198:13)
at emitCloseNT (net.js:1619:8)
at process._tickCallback (internal/process/next_tick.js:63:19)
(node:21) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:21) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
1) should respond 403 when no token is provided

0 passing (2s)
1 failing
1) authenticated ping
should respond 403 when no token is provided:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/usr/src/app/test/index.js)

在堆栈跟踪中,我可以看到达到了预期的测试结果,因为将响应200与预期的403进行比较,并且该部分现在看起来很好,但在那之后,测试用例超时并因此失败。我认为这是意料之中的事,因为done()从未被调用过,我觉得我理解这里发生的事情。

但是,在我的第一次尝试中会发生什么?我该如何解决?事实上,它看起来比后一种尝试更有效,但我不明白为什么请求被发送了两次?

我相信我现在已经解决了问题,它与异步调用无关。

编写方法的正确方法似乎是

'use strict';
const request = require('supertest');
const app = require('../server');
const keycloak = require('./util/keycloak-mock');
describe("authenticated ping", function() {
it("should respond 403 when no token is provided", function(done) {
keycloak.fetchToken()
.then((token) => request(app)
.get("/auth_ping")
.expect(403)
.end(done);
);
});
});

我在mocha中使用supertest的简短教程中似乎包含了一个可能不好的做法,建议将我自己的方法添加到end((函数中。当测试成功时,这种方法可以正常工作,但如果测试在某个期望值上失败,则会中断。

我在任何地方都没有找到它,但我测试的结果似乎是,你必须用end(done(结束命令链,或者将done作为附加参数添加到链中的最后一个期望值中(但不添加到任何早期的(。因此,与其添加end(done(,我还可以省略它,并使用expect(403,done(结束链。不过,目前我更喜欢显式结束,因为这样更容易在不破坏任何内容的情况下向链中添加额外的期望。

最新更新