Mocha 不支持您仅通过设置标志来执行的操作。最接近的是it
不带回调使用:
`it("foo")`
Mocha 将按此方式处理此测试pending
并进行报告。这与使用it.skip(...)
. 然而,测试并没有失败,它也没有捕捉到愚蠢的错误,比如有一个实际上没有迭代的循环:
it("foo", function () {
var a = something();
for (var i = 0; i < a.length; ++i) {
expect(a[i]).to...
}
});
如果碰巧这a
是一个长度为 0 的数组,那么您将不会测试任何东西,并且测试将通过。在这种情况下,我测试数组不是 0 长度,但仍然......
所以没有直接的方法可以做到这一点,而且 Mocha 没有为断言库提供 API 来告诉 Mocha 它们实际上已在测试中使用。不过,您可以构建自己的解决方案。这是一个概念证明:
var real_expect = require("chai").expect;
var expect_called = 0;
function expect() {
expect_called++;
return real_expect.apply(this, arguments);
}
var real_it = it;
it = function (name, fn) {
if (!fn.length) {
// Handle the case where `fn` is declared to be synchronous.
real_it(name, function () {
expect_called = 0;
fn.call(this);
if (expect_called === 0)
throw new Error("test did not call expect");
});
}
else {
// Handle the case where `fn` is declared to be asynchronous.
real_it(name, function (real_done) {
expect_called = 0;
function done () {
if (expect_called === 0) {
done(new Error("test did not call expect"));
return;
}
real_done();
}
fn.call(this, done);
});
}
};
it("foo", function () {
expect(1).to.equal(1);
});
it("foo async", function (done) {
setTimeout(function () {
expect(1).to.equal(1);
done();
}, 1000);
});
it("bar", function () {});
it("bar 2", function () {});
在上面的代码中,我们替换it
为我们自己的,它会进行检查,并expect
在调用它时替换为我们自己的标记。
关于异步测试和共享状态的说明。有时人们认为,如果将 Mocha 标记为异步,它们会同时运行多个。通常情况并非如此。Mocha 在异步测试之后继续等待两件事之一:测试调用其done
回调或超时。如果较早的测试超时,您可以同时运行来自两个测试的代码,并且碰巧超时的测试实际上是在等待异步操作在之后完成超时。在这种情况下,如果两个测试都依赖于任何状态,超时可能会导致级联测试失败(或级联测试成功!)。这是 Mocha 的普遍问题。一旦超时问题得到解决,那么级联效应将消失,后续测试将根据自身的优点成功或失败,而不会受到早期超时的异步测试的影响。在上面的代码中,expected_called
是所有测试所依赖的状态。所以超时可能会导致级联效应。
为了解决这个问题,每个测试都必须有它自己的私有实例expect
,这只会增加它自己的私有计数器。这可以按如下方式完成:
var real_expect = require("chai").expect;
var real_it = it;
it = function (name, fn) {
if (!fn.length) {
// Handle the case where `fn` is declared to be synchronous.
real_it(name, function () {
var expect_called = 0;
this.expect = function () {
expect_called++;
return real_expect.apply(this, arguments);
};
fn.call(this);
if (expect_called === 0)
throw new Error("test did not call expect");
});
}
else {
// Handle the case where `fn` is declared to be asynchronous.
real_it(name, function (real_done) {
var expect_called = 0;
this.expect = function () {
expect_called++;
return real_expect.apply(this, arguments);
};
function done () {
if (expect_called === 0) {
done(new Error("test did not call expect"));
return;
}
real_done();
}
fn.call(this, done);
});
}
};
it("foo", function () {
this.expect(1).to.equal(1);
});
it("foo async", function (done) {
var me = this;
setTimeout(function () {
me.expect(1).to.equal(1);
done();
}, 1000);
});
it("bar", function () {});
it("bar 2", function () {});
但缺点是您现在必须访问expect
as this.expect
,这意味着编写测试的方式与通常不同。您可能认为expect
在每次测试之前设置全局将消除使用的需要,this
但这种方法会遇到与我上面讨论的完全相同的问题。(测试共享的全局状态将是expect
它本身而不是expect_called
。)