2

我正在尝试使用 QUnit 来测试一堆 javascript。我的代码看起来像这样:

module("A");
doExpensiveSetupForModuleA();
asyncTest("A.1", testA1);
asyncTest("A.2", testA3);
asyncTest("A.3", testA3);

module("B");
doExpensiveSetupForModuleB();
asyncTest("B.1", testB1);
asyncTest("B.2", testB3);
asyncTest("B.3", testB3);

如果我按原样doExpensiveSetupForModuleB()运行,则在异步测试运行时运行,导致失败。

如果doExpensiveSetupForModuleB()在之前运行testA*,那么这些测试要么失败,要么撤消昂贵的设置工作,从而testB*失败。

有没有办法在下一个模块上有 QUnit 块?或者让它阻止开始一个新的测试,直到之前的异步测试完成?或者我应该使用更好的 JS 测试框架吗?

注意:我知道我的单元测试不是完全原子的。我确实有清理代码,可以帮助确保我没有得到任何脏状态,但doExpensiveSetupFor*()成本高得令人望而却步,因此在每次测试之前运行它是不现实的。

4

3 回答 3

2

你可以使用模块生命周期吗?

function runOnlyOnce(fn) {
    return function () {
        try {
            if (!fn.executed) {
                fn.apply(this, arguments);
            }
        } finally {
            fn.executed = true;
        }
    }
}

// http://api.qunitjs.com/module/
module("B", {
    setup: runOnlyOnce(doExpensiveSetupForModuleB)
});
于 2013-05-02T23:09:38.397 回答
1

这是一个示例,改编自您的原始代码,它为每个测试方法执行 setup 方法:

function doExpensiveSetupForModuleA() {
    console.log("setup A");
}

function testA1() {
    console.log("testA1");
    start();
}

function testA2() {
    console.log("testA2");
    start();
}

function testA3() {
    console.log("testA3");
    start();
}

function doExpensiveSetupForModuleB() {
    console.log("setup B");
}

function testB1() {
    console.log("testB1");
    start();
}

function testB2() {
    console.log("testB2");
    start();
}

function testB3() {
    console.log("testB3");
    start();
}

QUnit.module("A", { setup: doExpensiveSetupForModuleA });
    asyncTest("A.1", testA1);
    asyncTest("A.2", testA2);
    asyncTest("A.3", testA3);

QUnit.module("B", { setup: doExpensiveSetupForModuleB });
    asyncTest("B.1", testB1);
    asyncTest("B.2", testB2);
    asyncTest("B.3", testB3);

这将独立于执行测试的顺序,也独立于每个方法终止所花费的时间。

对 start() 的调用将确保仅在方法的该点收集测试结果。

更详细的示例可以在 QUnit Cookbook 中找到:http: //qunitjs.com/cookbook/#asynchronous-callbacks

更新: 如果您不希望在每个测试方法之前执行昂贵的方法,但实际上每个模块只执行一次,只需在代码中添加控制变量以检查模块是否已设置:

var moduleAsetUp = false;
var moduleBsetUp = false;

function doExpensiveSetupForModuleA() {
    if (!moduleAsetUp) {
        console.log("setting up module A");
        moduleAsetUp = true;
    }
}

...

function doExpensiveSetupForModuleB() {
    if (!moduleBsetUp) {
        console.log("setting up module B");
        moduleBsetUp = true;
    }
}
...

在此示例中,输出将是:

setting up module A 
 testA1 
 testA2 
 testA3 
 setting up module B 
 testB1 
 testB2 
 testB3 

这样,您就可以使用昂贵的方法作为模块设置,而不是测试方法设置。

单元测试应该是原子的、独立的、隔离的,因此它们运行的​​顺序不应该是相关的。

Qunit 并不总是以相同的顺序运行测试,无论如何,如果你希望你的测试以特定的顺序运行,你可以告诉 QUnit 不要重新排序它们:

QUnit.config.reorder = false;

这样您可以确保 testA 将在 testB 之前运行。

于 2013-05-09T22:00:45.880 回答
0

我认为您对测试声明的工作方式有误解。

QUnit 可以独立运行任何测试。仅仅因为您使用 test() 或 asyncTest() 声明测试并不意味着 QUnit 将调用传入的函数。每个测试旁边的“重新运行”链接重新加载页面并跳过除特定测试之外的每个测试。

因此,如果您想重新运行 B 模块测试,您的代码将设置 A 模块,即使它不需要。

其他人发布的模块设置解决方案可能是这里的方式。

于 2014-05-23T15:39:47.183 回答