【问题标题】:Could someone explain the use of qunit-fixture when unit testing with QUnit?有人可以在使用 QUnit 进行单元测试时解释 qunit-fixture 的使用吗?
【发布时间】:2015-11-12 20:55:53
【问题描述】:

我刚刚开始使用 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 中放置一个 iframe,它将隔离测试环境和支持代码。

标签: javascript unit-testing qunit


【解决方案1】:

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

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

在您的情况下,您正在创建一个空的 qunit-fixture div 并从另一个 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-fixture div,您可以从测试中删除这些行:

    $("#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-fixture 之外没有标记,除了 QUnit 将用于测试结果的 qunit div 之外,没有“qunit-fixture 之外的页面部分”,正如您在评论中所写的那样,也没有有没有重复的ID。

【讨论】:

  • 这并不能消除重复 ID 的问题,因为 ID 仍然存在于 qunit-fixture 之外的页面部分中。此外,populate() 仍然会破坏 DOM 的那部分。基本上将所有标记复制到 qunit-fixture 中似乎也是一个巨大的性能损失(页面大小)。
  • @thedarklord47:看来我们的波长差不多。据我所知,QUnit 旨在用于我已编辑的答案中包含的表单的静态 HTML 页面。这就是你运行 QUnit 的方式吗?如果没有,你是如何运行它的?你的 HTML 来自哪里?
  • 页面不是静态的。它是 laravel web 应用程序的一部分,带有额外的 Handlebars 模板。不过那应该没关系。我的问题是:根据定义,操纵 DOM 的函数(我要测试的函数)将操纵 DOM。添加一个隐藏的qunit-fixture 会重置每个测试,并不会改变这一事实。此外,将标记插入qunit-fixture 以模拟页面中正在发生的事情,会导致 ID 不唯一,显然不是这样做的方法。您是说 QUnit 根本不打算在真实页面上运行吗?像我需要建立一个单独的测试沙箱?
  • @thedarklord47:是的,我想说 QUnit 不打算在真实页面上运行。恐怕我没有使用过 Laravel 和 Handlebars,所以我不知道为你准备一个测试沙箱需要做多少工作。
  • 啊。好吧..不是很容易,但这更有意义。谢谢你的解释
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多