有人可以解释使用 QUnit 进行单元测试时 qunit-fixture 的使用吗?

the*_*d47 4 javascript unit-testing qunit

我刚刚开始使用 QUnit 进行 ui 测试,所以我确定我错过了 qunit-fixture 的一些基本用例。我认为它对测试 DOM 操作很有用,但后来我意识到我的 DOM 操作函数都不知道 qunit-fixture(也不应该?)。

例子:

<div id="container">
    <form id="my-form">
        <input type="hidden" name="field1" id="field1">
        <input type="hidden" name="field2" id="field2">
    </form>
</div>
<div id="qunit-fixture"></div>
Run Code Online (Sandbox Code Playgroud)

我将 URL 参数传递给一个函数来填充这个表单。如果这些参数不存在,我希望删除该字段,以免JQuery.serialize()捆绑一个空字段。

function populate(params){
    if( params.field1 ){
        $("#field1").val(params.field1);
    } else {
        $("#field1").remove();
    }
    if( params.field2 ){
        $("#field2").val(params.field2);
    } else {
        $("#field2").remove();
    }
}
Run Code Online (Sandbox Code Playgroud)

我最初的想法是“哦,酷。我可以qunit-fixture用来反复模仿我的形式!” 像这样:

QUnit.test("populate - field1=text", function(assert){
    $("#qunit-fixture").html($("#container").html());
    populate( {field1: "text"} );

    assert.deepEqual($("#field1").val(), "text");
    assert.deepEqual($("#field2").val(), undefined);
});

QUnit.test("populate - field1="text", function(assert){
    $("#qunit-fixture").html($("#container").html());
    populate( {field1: "text", field2: "text"} );

    assert.deepEqual($("#field1").val(), "text");
    assert.deepEqual($("#field2").val(), "text");
});
Run Code Online (Sandbox Code Playgroud)

这当然失败了,因为第一个测试调用populate()改变了 DOM 并#field2从页面的主表单中删除除了被放入qunit-fixture(非唯一 IDs.. yikes)的副本之外。

那么我错过了什么?我真的很喜欢用 QUnit 测试逻辑模块的能力,并且终于开始看到更多测试驱动的开发风格的优点。我也希望能够测试我的 DOM 操作。

注意:这是一个简单的例子。我的项目中实际的 DOM 操作要复杂得多,因此需要对其进行测试。

Luk*_*ard 6

qunit-fixture元素是一些 HTML 的容器,您的测试可以针对这些 HTML 进行断言。每次测试后,QUnit 都会将其重置回测试开始前的状态,以便下一个测试可以运行,而不必担心上一个测试添加或删除了什么。

当然,如果您的测试开始对外部元素进行修改qunit-fixture,那么您将开始看到测试影响其他测试,所以尽量不要这样做。

在您的情况下,您正在创建一个空的qunit-fixturediv 并从另一个 div 复制内容。更好的方法是使用qunit-fixture元素来包含要测试的 HTML,例如:

<div id="qunit-fixture">
    <div id="container">
        <form id="my-form">
            <input type="hidden" name="field1" id="field1">
            <input type="hidden" name="field2" id="field2">
        </form>
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)

(我不知道你是否需要容器div。我在上面的例子中保留了它,但如果没有必要,请随意删除它。)

由于您不再需要将容器 div 中的 HTML 复制到qunit-fixturediv 中,因此您可以从测试中删除这些行:

    $("#qunit-fixture").html($("#container").html());
Run Code Online (Sandbox Code Playgroud)

您也不再有重复 ID 的问题,并且由于 QUnit 将qunit-fixture在每次测试后重置,因此您的一个测试不应该影响另一个。

QUnit 的目的是从专门为测试目的而创建的页面运行它。此页面应如下所示:

<html>
<head>
  <!-- load various JS and CSS files -->
</head>
<body>
  <div id="qunit"></div>
  <div id="qunit-fixture">
    <!-- sample markup for testing against -->
  </div>
</body>
Run Code Online (Sandbox Code Playgroud)

由于除了QUnit 将用于测试结果qunit-fixturequnitdiv之外没有任何标记,因此没有“页面外部的部分qunit-fixture”,正如您在评论中所写,也没有任何重复的 ID。