如何异步构建我的测试套件?

时间:2016-07-08 13:53:14

标签: node.js mocha

我正在尝试使用必须加载异步的配置为我的控制器创建mocha测试。以下是我的代码。但是,当运行mocha测试时,它不会运行任何测试,显示0 passing。永远不会调用console.log。我尝试在describe中执行before(next => config.build().then(next)),但即使测试运行,也永远不会调用before。有没有办法在运行任何测试之前加载一次配置?

'use strict';

const common = require('./common');
const config = require('../config');

config
    .build()
    .then(test);


function test() {
console.log(1);
    describe('Unit Testing', () => {
console.log(2);
        require('./auth');
    });
}

3 个答案:

答案 0 :(得分:3)

您应该使用--delay选项运行Mocha,然后在构建完测试套件后使用run()。以下是从您在问题中显示的代码派生的示例:

'use strict';

function test() {
    console.log(1);
    describe('Unit Testing', () => {
        console.log(2);
        it("test", () => {
            console.log(3);
        });
    });

    // You must use --delay for `run()` to be available to you.
    run();
}

setTimeout(test, 1000);

我使用setTimeout来模拟异步操作。使用--delayrun()可以构建一个异步计算结果的套件。但请注意,套件必须一次性构建。 (你不能在describe内部有一个异步过程来调用it。这不会起作用。)

你绝对不应该做的一件事是rob3c suggests:在一个钩子内调用describeit(或两者)。这是一个偶尔人们所犯的错误,因此值得详细解决。问题是它不受Mocha支持,因此没有与从钩子内部调用describeit相关联的已建立语义。哦,有可能编写简单的例子,这些例子可以按照人们的预期工作,但是:

  1. 当套件变得更加复杂时,套件的行为不再符合任何合理的行为。

  2. 由于没有与此方法相关的语义,较新的Mocha版本可能会以不同方式处理错误使用并破坏您的套件。

  3. 考虑这个简单的例子:

    const assert = require("assert");
    
    const p = Promise.resolve(["foo", "bar", "baz"]);
    
    describe("top", () => {
        let flag;
        before(() => {
            flag = true;
            return p.then((names) => {
                describe("embedded", () => {
                    for (const name of names) {
                        it(name, () => {
                            assert(flag);
                        });
                    }
                });
            });
        });
    
        after(() => {
            flag = false;
        });
    
        it("regular test", () => {
            assert(flag);
        });
    });
    

    当我们运行它时,我们得到:

      top
        ✓ regular test
    
      embedded
        1) foo
        2) bar
        3) baz
    
      1 passing (32ms)
      3 failing
    
      // [stack traces omitted for brevity]
    

    这里发生了什么?所有的测试都不应该通过吗?我们在flag描述的true挂钩中将before设置为top。我们在其中创建的所有测试都应将flag视为true,不是吗?线索在上面的输出中:当我们在钩子中创建测试时,Mocha会将测试放在某处,但它可能不在反映describe块结构的位置代码。在这种情况下发生的事情是Mocha只是在top描述之外的套件的最末端附加钩子中创建的测试,因此after钩子运行之前动态创建的测试,我们得到一个反直觉的结果。

    使用--delayrun(),我们可以编写一个行为方式与直觉相符的套件:

    const assert = require("assert");
    
    const p = Promise.resolve(["foo", "bar", "baz"]).then((names) => {
        describe("top", () => {
            let flag;
            before(() => {
                flag = true;
            });
    
            after(() => {
                flag = false;
            });
    
            describe("embedded", () => {
                for (const name of names) {
                    it(name, () => {
                        assert(flag);
                    });
                }
            });
    
            it("regular test", () => {
                assert(flag);
            });
        });
        run();
    });
    

    输出:

      top
        ✓ regular test
        embedded
          ✓ foo
          ✓ bar
          ✓ baz
    
    
      4 passing (19ms)
    

答案 1 :(得分:-1)

你可以完全分开测试和加载的逻辑,将加载器包装在一个阻止测试的promise中,直到执行配置(如果使用node8,则使用async / await非常简单,否则只是Promise.each结果)。

如果你真的不想这样做,你可以Promisify你的测试框架,这将允许你将所有describe / it块视为异步代码。

答案 2 :(得分:-1)

使用@Louis在其接受的答案中提到的--delay命令行标记和run()回调的问题是run()单个全局钩子delays the root test suite。因此,你必须立即构建它们(如他所提到的),这可能使组织测试变得麻烦(至少可以说)。

但是,我希望尽可能避免使用魔术标记,而且我当然不希望在一个全局run()回调中管理我的整个测试套件。幸运的是,有一种方法可以基于每个文件动态创建测试,并且它不需要任何特殊标志: - )

要使用异步获取的数据在任何测试源文件中动态创建It()测试,您可以(ab)将before()挂钩与占位符It()一起使用测试以确保mocha等待运行before()。以下是my answer to a related question的示例,为方便起见:

before(function () {
    console.log('Let the abuse begin...');
    return promiseFn().
        then(function (testSuite) {
            describe('here are some dynamic It() tests', function () {
                testSuite.specs.forEach(function (spec) {
                    it(spec.description, function () {
                        var actualResult = runMyTest(spec);
                        assert.equal(actualResult, spec.expectedResult);
                    });
                });
            });
        });
});

it('This is a required placeholder to allow before() to work', function () {
    console.log('Mocha should not require this hack IMHO');
});