有人能解释一下在用qunit进行单元测试时使用qunit夹具吗

Could someone explain the use of qunit-fixture when unit testing with QUnit?

本文关键字:qunit 单元测试 夹具 能解释 一下      更新时间:2023-09-26

我刚刚开始使用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>

我正在将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();
    }
}

我最初的想法是"哦,太酷了。我可以用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");
});

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

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

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

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>

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

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

    $("#qunit-fixture").html($("#container").html());

您也不再有重复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>

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