2012-03-16 70 views
42

这个问题涉及到NodeJS的Mocha测试框架。如何按顺序执行异步摩卡测试(NodeJS)?

默认的行为似乎是启动所有的测试,然后处理异步回调,因为他们进来,

当运行异步测试,我想的异步部分后运行每个测试一个之前被称为。

我该怎么做?

回答

30

重点不在于“结构化代码按照您构建它的顺序运行”(令人惊叹!) - 而是如@ chrisdew所示,异步测试的返回订单无法得到保证。为了重新说明问题 - 进一步在(同步执行)链下的测试不能保证由异步测试设置的所需条件将在他们运行时做好准备。

因此,如果您要求在第一次测试中设置某些条件(如登录令牌或类似条件),则必须使用钩子(如before())来测试在继续之前设置的条件。

裹在一个块中的相关测试和运行它们的异步before钩(注意“做”的前挡):

var someCondition = false 

// ... your Async tests setting conditions go up here... 

describe('is dependent on someCondition', function(){ 

    // Polls `someCondition` every 1s 
    var check = function(done) { 
    if (someCondition) done(); 
    else setTimeout(function(){ check(done) }, 1000); 
    } 

    before(function(done){ 
    check(done); 
    }); 

    it('should get here ONLY once someCondition is true', function(){ 
    // Only gets here once `someCondition` is satisfied 
    }); 

}) 
+0

如果before回调在while循环中被锁定,'someCondition'会如何改变?!这不是JavaScript的工作方式。 – natevw 2013-06-03 19:50:08

+0

你的问题的答案在评论第3行:“..你的异步测试设置条件上升到这里”。具体来说就是:异步,设置条件,范围在'before()'之前实例化的'describe()'之外。你后来对Javascript的断言不是以这种方式工作是错误的。 – papercowboy 2013-06-04 22:31:14

+0

当您的代码被反复检查!someCondition时,您的其他代码都无法运行。 (与事件/定时器相关的所有其他回调将被阻止执行。)这将工作的唯一方法是,如果someCondition在循环开始之前设置为true,否则它将挂起。尝试一下。 – natevw 2013-06-05 05:46:51

7

我很惊讶你写的,因为我使用。我用bdd风格测试(描述/它)来使用摩卡,并且只是在我的测试中添加了一些console.logs,以查看您的声明是否适合我的情况,但看起来他们没有。

以下是我用来查看“end1”和“start1”顺序的代码片段。他们被妥善订购。

describe('Characters start a work', function(){ 
    before(function(){ 
     sinon.stub(statusapp, 'create_message'); 
    }); 
    after(function(){ 
     statusapp.create_message.restore(); 
    }); 
    it('creates the events and sends out a message', function(done){ 
     draftwork.start_job(function(err, work){ 
     statusapp.create_message.callCount.should.equal(1); 
     draftwork.get('events').length.should.equal(
      statusapp.module('jobs').Jobs.get(draftwork.get('job_id')).get('nbr_events') 
     ); 
     console.log('end1'); 
     done(); 
     }); 
    }); 
    it('triggers work:start event', function(done){ 
     console.log('start2'); 
     statusapp.app.bind('work:start', function(work){ 
     work.id.should.equal(draftwork.id); 
     statusapp.app.off('work:start'); 
     done(); 
     }); 

当然,这可能是偶然发生过,但我有很多的测试,如果他们将并行运行,我一定会有竞争条件,我没有。请参阅this issue。根据它,测试是同步运行的。

+0

这只显示有序代码按顺序运行。这不是偶然发生的。这是“它是如何工作的”。 – papercowboy 2012-10-19 22:55:16

+0

这表明按顺序运行异步测试:'end1'将始终发生在'start2'之前。为了简化示例,您可以用'setTimeout(done,1000)'替换第一个测试的内容。如果用异步代码替换'before'钩子,它会在第一次测试之前始终运行。据我所知,这正是主题启动者感兴趣的行为,并且这种行为是默认行为,也是唯一的行为,至少到目前为止。 – skozin 2014-09-21 02:09:33

5

我想解决这个同样的问题与我们的应用,但accepted answer并不适合我们。特别是在someCondition永远不会是真的。

我们在我们的应用程序中使用承诺,这些使得它很容易相应地构建测试。然而,关键的还是通过before钩到延迟执行:

var assert = require("assert"); 

describe("Application", function() { 
    var application = require(__dirname + "/../app.js"); 
    var bootPromise = application.boot(); 

    describe("#boot()", function() { 
    it("should start without errors", function() { 
     return bootPromise; 
    }); 
    }); 

    describe("#shutdown()", function() { 
    before(function() { 
     return bootPromise; 
    }); 

    it("should be able to shut down cleanly", function() { 
     return application.shutdown(); 
    }); 
    }); 
}); 
+3

我最好将第二行和第三行代码('application = ...'和'bootPromise = ...')放在顶级套件(“应用程序”)中的async'before'块之内。否则,从该代码抛出的任何异常都不会被捕获并正确报告,更糟糕的是,将阻止执行所有剩余的测试。 – skozin 2014-09-21 01:59:38

4

使用mocha-steps

它使测试顺序,不管它们是异步与否(即你done功能仍能正常工作,正是因为他们做了)。它是it的直接替代品,而不是您使用的step

+0

这是为什么这个投票? – 2016-11-21 18:20:36

+1

@JackMurphy很好的问题。 – WiR3D 2016-11-24 12:18:58

+0

相同。我有同样的问题,这帮助了我。 – hrishioa 2016-12-14 01:47:45