unit-testing - 没有期望时如何使 Mocha 失败()

标签 unit-testing tdd mocha.js karma-mocha mocha-phantomjs

如果 it() 函数中没有提供期望,是否可以设置 mocha 以将测试报告为失败?

想法是这样的工作流程:

  • 添加一个带有 desc 和回调函数的 it()
  • it() 被报告为失败,因为在回调
  • 中未设置期望值
  • 期望增加
  • it() 仍然报告为失败,因为没有实现
  • 没有满足预期
  • 添加实现
  • it() 被报告为成功
  • 重构

  • 因此,主要意图是在进行规范 TDD 样式开发时,新添加的测试报告为失败,直到设置期望(或测试集为未决而没有回调或跳过()),这再次报告为失败,一旦实现完成,报告为成功。

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

    此外,如果有人知道如何在 karma.conf.js 中进行设置,那就太好了。

    谢谢

    最佳答案

    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是所有测试都依赖的状态。 所以超时可能会导致级联效应。

    为了解决这个问题,每个测试都必须有自己的私有(private)实例 expect。 ,这只会增加自己的私有(private)计数器。这可以按如下方式完成:
    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 () {});
    

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

    关于unit-testing - 没有期望时如何使 Mocha 失败(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30971393/

    相关文章:

    c# - 设置 Mock 以返回我发送给它的同一个对象?

    ruby - Michael Hartl 的 Rails 5 教程第 10 章, list 10.56,测试 admin 属性是否被禁止

    asp.net-mvc - 为 ASP.Net MVC 设置测试的最佳实践是什么?使用/处理/等什么?

    node.js - Mocha 测试失败 "MongoError: server sockets closed"

    c# - 集成测试详细

    javascript - Travis-CI +(BrowserStack 或其他浏览器提供商)?

    ios - 如何在 XCode 5 中对每个 "build and run"操作自动执行单元测试?

    c# - 完全运行时单元测试失败 - API 限制 : The assembly has already loaded from a different location

    typescript - 如何在 Typescript 中使用 Chai expect() 验证特定类型?

    javascript - 函数不能被 Mocha/Sinon 模拟/ stub