【发布时间】:2012-04-01 22:43:16
【问题描述】:
这个问题与 NodeJS 的 Mocha 测试框架有关。
默认行为似乎是启动所有测试,然后在异步回调进入时处理它们。
在运行异步测试时,我想在调用之前的异步部分之后运行每个测试。
我该怎么做?
【问题讨论】:
标签: javascript node.js mocha.js
这个问题与 NodeJS 的 Mocha 测试框架有关。
默认行为似乎是启动所有测试,然后在异步回调进入时处理它们。
在运行异步测试时,我想在调用之前的异步部分之后运行每个测试。
我该怎么做?
【问题讨论】:
标签: javascript node.js mocha.js
无论它们是否异步,它都会使测试保持顺序(即您的 done 函数仍然像它们一样工作)。它是it 的直接替代品,而您使用step
【讨论】:
我想用我们的应用程序解决同样的问题,但accepted answer 对我们来说效果不佳。尤其是在someCondition 永远不会是真的。
我们在应用程序中使用了 Promise,这使得相应地构建测试变得非常容易。然而,关键仍然是通过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();
} );
} );
} );
【讨论】:
application = ... 和bootPromise = ...)放在顶层套件(“应用程序”)的异步before 块中。否则,此代码引发的任何异常都不会被正确捕获和报告,更糟糕的是,会阻止所有剩余测试的执行。
重点不在于“结构化代码按照您构建它的顺序运行”(惊奇!)——而是正如@chrisdew 所建议的那样,异步测试的返回顺序不能得到保证。重申一下这个问题 - (同步执行)链更下游的测试不能保证由异步测试设置的所需条件将在它们运行时准备好。
因此,如果您需要在第一次测试中设置某些条件(例如登录令牌或类似的),您必须使用像 before() 这样的钩子来测试这些条件是否已设置,然后再继续。
将依赖测试包装在一个块中并在它们上运行 async 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
});
})
【讨论】:
someCondition 将如何改变?!这不是 JavaScript 的工作方式。
describe() 之外,在before() 之前实例化。您关于 Javascript 不能以这种方式工作的后一个断言是错误的。
before 挂钩在第一个测试之前运行,无论是异步的还是同步的)。唯一需要轮询机制的情况是设置异步条件的代码不接受回调并且不返回承诺。
我对您在我使用时所写的内容感到惊讶。我将 mocha 与 bdd 样式测试(describe/it)一起使用,并在我的测试中添加了一些 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();
});
当然,这也可能是偶然发生的,但我有很多测试,如果它们并行运行,我肯定会有竞争条件,而我没有。
请参阅 mocha 问题跟踪器中的 this issue。根据它,测试是同步运行的。
【讨论】:
end1 将始终出现在start2 之前。为了简化示例,您可以将第一个测试的内容替换为setTimeout(done, 1000)。如果您将 before 钩子替换为异步钩子,它将始终在第一次测试之前运行。据我了解,这正是主题启动者感兴趣的行为,而且这种行为是默认的,也是唯一的,至少现在是这样。