如何让mocha在没有预期的时候失败()

gee*_*ee6 6 tdd unit-testing mocha.js karma-mocha mocha-phantomjs

是否有一个选项可以设置mocha报告测试失败,如果在it()函数中没有提供预期的话?

Idea的工作流程如下:

  1. 使用desc和回调函数添加一个it()
  2. 因为在回调中没有设置期望,所以it()被报告为失败
  3. 期望被添加
  4. 因为没有实现,所以it()仍然报告为失败,因为没有达到预期
  5. 实施已添加
  6. it()被报告为成功
  7. 重构

所以主要意图是在进行规范TDD风格开发时,新增加的测试报告为失败,直到设置期望(或测试设置为挂起而没有回调或skip()),再次报告为失败,一旦执行完成,它报告为成功.

我看到它的价值()成功而没有期望的是,一旦它被添加它的失败现在证明它实际上正在工作并证明它失败了.是故意还是我错过了什么?

此外,如果有人知道如何在karma.conf中设置它.js会很棒.

谢谢

Lou*_*uis 2

Mocha 不支持仅仅通过设置一个标志来完成你想做的事情。it最接近的是在没有回调的情况下使用:

`it("foo")`
Run Code Online (Sandbox Code Playgroud)

Mocha 会如此对待此测试pending并如此报告。它与使用相同it.skip(...)。然而,测试并没有失败,并且它没有捕获愚蠢的错误,例如有一个实际上不迭代的循环:

it("foo", function () {
    var a = something();
    for (var i = 0; i < a.length; ++i) {
        expect(a[i]).to...
    }
});
Run Code Online (Sandbox Code Playgroud)

如果碰巧这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 () {});
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我们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 () {});
Run Code Online (Sandbox Code Playgroud)

但缺点是您现在必须访问expectas this.expect,这意味着以与通常不同的方式编写测试。您可能认为在每次测试之前设置全局expect将消除使用的需要this,但这种方法会遇到与我上面讨论的完全相同的问题。(测试共享的全局状态将是expect其本身而不是expect_called。)