使用mocha done()和async await时出现的悖论问题

10

我有以下测试用例:

it("should pass the test", async function (done) {
        await asyncFunction();
        true.should.eq(true);
        done();
    });

运行它会断言:

错误:解析方法已经过度指定。指定回调函数或返回Promise,而不是两者同时。

如果我删除done();语句,它会断言:

错误:超出2000ms的超时。对于异步测试和钩子,请确保调用"done()";如果返回Promise,请确保解决。

如何解决这个悖论?


3
当您删除done();时,是否也删除函数中的done参数? - T.J. Crowder
应该有一个返回语句吧?我认为所有同步函数都需要返回才能解决。 - Shyam Babu
@ShyamBabu:如果没有显式的return,一旦它们等待的最后一个Promise完成,它们就会解析为undefined - T.J. Crowder
@T.J.Crowder,我刚刚在函数签名中删除了done参数,现在它可以工作了!请将其重写为答案,我会接受的。 - Alon
@Alon:哈哈,一旦我证明了这个问题确实存在,我就开始写它了。现在完成了。 :-) - T.J. Crowder
3个回答

18

你需要删除done参数,而不仅仅是删除对它的调用。像Mocha这样的测试框架会查看函数的参数列表(或至少是其参数个数),以确定是否使用了done或类似参数。

在使用Mocha 3.5.3时,以下代码可以正常工作(由于前者会抛出错误,所以我将true.should.be(true)更改为assert.ok(true)):

const assert = require('assert');

function asyncFunction() {
    return new Promise(resolve => {
        setTimeout(resolve, 10);
    });
}

describe('Container', function() {
  describe('Foo', function() {
    it("should pass the test", async function () {
        await asyncFunction();
        assert.ok(true);
    });
  });
});

但如果我添加了done:

describe('Container', function() {
  describe('Foo', function() {
    it("should pass the test", async function (done) {  // <==== Here
        await asyncFunction();
        assert.ok(true);
    });
  });
});

...然后我遇到了

错误:超过2000毫秒的超时。对于异步测试和钩子,请确保调用“done()”;如果返回一个Promise,则确保它解决。


1
你救了我,我浪费了好几个小时寻找解决方案。 - Theophilus Omoregbee
@T.J Crowder 接下来是它(“应该通过...仍然存在问题”)的错误信息:“超时2000毫秒。对于异步测试和钩子,请确保调用“done()”;如果返回Promise,请确保它被解决。” - Aljohn Yamaro
@AljohnYamaro - 上面的示例中的Promise确实会被解决。它等待由asyncFunction返回的Promise解决,然后调用assert.ok(true),然后解决(通过返回)。 - T.J. Crowder
1
@T.J.Crowder 我想不需要了,我找到了解决方案。在 package.json 中应该是 "test": "mocha --timeout 60000",之前只有 "test": "mocha",这就是为什么它会显示 Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. 简而言之,时间必须延长。你的解决方案也可以。谢谢。 - Aljohn Yamaro
1
祝福你!真的,因为这个问题浪费了我好几个小时,不知道有多少。 - Yeshi
显示剩余4条评论

0
有时候在 mocha 中需要同时使用 async/awaitdone 函数。
例如,在我的一个 socket.io 单元测试中,我需要使用异步函数调用 db 函数,并测试回调函数的 socket 事件处理程序:
context("on INIT_CHAT", ()=> {
  it("should create a room", async (done) => {
    const user = await factory.create("User");
    socket.emit("INIT_CHAT", user);
    
    socket.on("JOIN_CHAT", async (roomId) => {
       const room = await ChatRoom.findByPk(roomId);
       expect(room).to.exist;
       // then I need to close a test case here
       done();
    });
  });
});

这将导致与 OP 中完全相同的错误:

错误:分辨率方法过度指定。指定回调或返回 Promise;不要同时使用两者。

我的解决方法:

我只是在一个 Promise 生成器中包装了整个测试代码:

context("on INIT_CHAT", ()=> {
  it("should create a room", async () => {
    const asyncWrapper = () => {
      return new Promise(async (resolve) => {
        const user = await factory.create("User");
        socket.emit("INIT_CHAT", user);
        socket.on("JOIN_CHAT", async (roomId) => {
          const room = await ChatRoom.findByPk(roomId);
          expect(room).to.exist;
          resolve(true);
        });
      });
    });
    await asyncWrapper();
  });
});

0

将“done”作为参数从中删除对我有用!只使用expect/should。示例如下:

getResponse(unitData, function callBack(unit, error, data){ try {
    return request.post(unit, function (err, resp) {
        if (!err && resp.statusCode === 200) {
            if (resp.body.error) {
                return callback(obj, JSON.stringify(resp.body.error), null); 
            }
            return callback(obj, null, resp); 
        } else {
            if (err == null) {  
                err = { statusCode: resp.statusCode, error: 'Error occured.' };
            }
            return callback(obj, err, null); 
        }
    });
} catch (err) {
    return callback(obj, err, null);
}}

之前:

it('receives successful response', async (done) => { 
const getSomeData = await getResponse(unitData, function callBack(unit, error, data){ 
    expect(data.statusCode).to.be.equal(200); 
    done(); 
}) })

之后(运行):

it('receives successful response', async () => { 
const getSomeData = await getResponse(unitData, function callBack(unit, error, data){
     expect(data.statusCode).to.be.equal(200); 
}) })

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接