QUnit系列 -- 2.介绍单元测试(下)

简介:   JavaScript测试框架:QUnit   下面我们将介绍使用QUnit来完成前一章中的单元测试。 DOCTYPE html> Refactored date examples test...

  JavaScript测试框架:QUnit

  下面我们将介绍使用QUnit来完成前一章中的单元测试。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Refactored date examples</title>
 
    <link rel="stylesheet" href="../qunit.css" />
    <script src="../qunit.js"></script>
    <script src="prettydate.js"></script>
 
    <script>
    test("prettydate basics", function() {
        var now = "2008/01/28 22:25:00";
        equal(prettyDate(now, "2008/01/28 22:24:30"), "just now");
        equal(prettyDate(now, "2008/01/28 22:23:30"), "1 minute ago");
        equal(prettyDate(now, "2008/01/28 21:23:30"), "1 hour ago");
        equal(prettyDate(now, "2008/01/27 22:23:30"), "Yesterday");
        equal(prettyDate(now, "2008/01/26 22:23:30"), "2 days ago");
        equal(prettyDate(now, "2007/01/26 22:23:30"), undefined);
    });
    </script>
</head>
<body>
    <div id="qunit"></div>
</body>
</html>

  运行实例

 

  这里有三点需要注意。

  首先,我们包含了三个文件:两个和 QUnit 相关(qunit.css and qunit.js) ,另一个是包含测试函数的prettydate.js。

  其次,是断言部门的脚本。test方法只会调用一次,第一个参数是测试名称,第二个参数是实际的测试代码。然后代码定义了变量now,便于后面使用。接下来使用equal方法来执行断言操作,他是QUnit提供的一系列方法中的一个。第一个参数是函数执行后的结果,第二个参数是期望值,如果两个值一致则断言通过,否则就失败。

  最后,页面body中包含一些和QUnit相关的标签,这些元素是可选的。如果我们使用了,QUnit会使用他们来输出结果。

输出结果:

包含失败的输出结果:

 

  因为测试包含一个失败的断言,所以QUnit没有把结果收起来,我们可以马上看到错误。我们把期望值和实际值都显示了出来,还显示了他们的不同点,这样对于我们找到问题很有帮助。

 

  重构:2

  我们的断言还没结束,还没有判断“几个星期”的情况。 再次之前,我们再把代码重构下。现在的版本每次断言的时候,都会去调用 prettyDate,并传递 now 参数。 我们可以重构一个自定义的断言函数:

test("prettydate basics", function() {
    function date(then, expected) {
        equal(prettyDate("2008/01/28 22:25:00", then), expected);
    }
    date("2008/01/28 22:24:30", "just now");
    date("2008/01/28 22:23:30", "1 minute ago");
    date("2008/01/28 21:23:30", "1 hour ago");
    date("2008/01/27 22:23:30", "Yesterday");
    date("2008/01/26 22:23:30", "2 days ago");
    date("2007/01/26 22:23:30", undefined);
});

  运行实例

  这样我们就把prettyDate封装到了date函数中,date里面会提供now变量,这样外面使用的时候就不需要再传递了。这样会让我们的代码更简单。

  

  测试DOM操作

  现在prettyDate已经可以被很好的测试了,让我们回过头来看之前的例子。借助于window的load事件,我们可以使用prettyDate函数选择DOM元素并更新他们。和之前一样,我们需要重构他并使之能够测试。另外,我们把两个方法放到同一个模块中,避免命名空间的混乱并且让代码更容易维护。

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Refactored date examples</title>
    <link rel="stylesheet" href="../qunit.css" />
    <script src="../qunit.js"></script>
    <script src="prettydate2.js"></script>
    <script>
    test("prettydate.format", function() {
        function date(then, expected) {
            equal(prettyDate.format("2008/01/28 22:25:00", then), expected);
        }
        date("2008/01/28 22:24:30", "just now");
        date("2008/01/28 22:23:30", "1 minute ago");
        date("2008/01/28 21:23:30", "1 hour ago");
        date("2008/01/27 22:23:30", "Yesterday");
        date("2008/01/26 22:23:30", "2 days ago");
        date("2007/01/26 22:23:30", undefined);
    });
 
    test("prettyDate.update", function() {
        var links = document.getElementById("qunit-fixture").getElementsByTagName("a");
        equal(links[0].innerHTML, "January 28th, 2008");
        equal(links[2].innerHTML, "January 27th, 2008");
        prettyDate.update("2008-01-28T22:25:00Z");
        equal(links[0].innerHTML, "2 hours ago");
        equal(links[2].innerHTML, "Yesterday");
    });
 
    test("prettyDate.update, one day later", function() {
        var links = document.getElementById("qunit-fixture").getElementsByTagName("a");
        equal(links[0].innerHTML, "January 28th, 2008");
        equal(links[2].innerHTML, "January 27th, 2008");
        prettyDate.update("2008/01/29 22:25:00");
        equal(links[0].innerHTML, "Yesterday");
        equal(links[2].innerHTML, "2 days ago");
    });
    </script>
</head>
<body>
    <div id="qunit"></div>
    <div id="qunit-fixture">
        <ul>
            <li class="entry" id="post57">
                <p>blah blah blah...</p>
                <small class="extra">
                    Posted <span class="time"><a href="/2008/01/blah/57/" title="2008-01-28T20:24:17Z">January 28th, 2008</a></span>
                    by <span class="author"><a href="/john/">John Resig</a></span>
                </small>
            </li>
            <li class="entry" id="post57">
                <p>blah blah blah...</p>
                <small class="extra">
                    Posted <span class="time"><a href="/2008/01/blah/57/" title="2008-01-27T22:24:17Z">January 27th, 2008</a></span>
                    by <span class="author"><a href="/john/">John Resig</a></span>
                </small>
            </li>
        </ul>
    </div>
</body>
</html>

  prettydate2.js代码:

var prettyDate = {
    format: function(now, time){
        var date = new Date(time || ""),
            diff = (((new Date(now)).getTime() - date.getTime()) / 1000),
            day_diff = Math.floor(diff / 86400);
 
        if ( isNaN(day_diff) || day_diff < 0 || day_diff >= 31 )
            return;
 
        return day_diff === 0 && (
                diff < 60 && "just now" ||
                diff < 120 && "1 minute ago" ||
                diff < 3600 && Math.floor( diff / 60 ) + " minutes ago" ||
                diff < 7200 && "1 hour ago" ||
                diff < 86400 && Math.floor( diff / 3600 ) + " hours ago") ||
            day_diff === 1 && "Yesterday" ||
            day_diff < 7 && day_diff + " days ago" ||
            day_diff < 31 && Math.ceil( day_diff / 7 ) + " weeks ago";
    },
 
    update: function(now) {
        var links = document.getElementsByTagName("a");
        for ( var i = 0; i < links.length; i++ ) {
            if ( links[i].title ) {
                var date = prettyDate.format(now, links[i].title);
                if ( date ) {
                    links[i].innerHTML = date;
                }
            }
        }
    }
};

  运行实例

 

  prettyDate.update方法是从之前例子中提取出来的,他含有now参数,方法里面把now传给了prettyDate.format。基于QUnit的测试,开始的时候会把所有包含在#qunit-fixture中的元素找出来。<div id="qunit-fixture">…</div>是页面新加入的标签,这里我们放置之前例子使用的DOM标签,这样我们就可以用于测试了。你不用担心这里DOM元素的改变会影响到其他的测试,因为QUnit会为每次测试重置这些标签的。

  这里你也许会有疑问,为什么测试页面没有显示<div id="qunit-fixture">…</div>的内容呢,原因是QUnit把他放在了一个离我们屏幕很远的地方,看截图:

 

 

  重构:3

  上面的代码还是有很多重复的内容,我们进一步重构,把测试DOM的测试抽到方法domtest中,方便多次调用:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Refactored date examples</title>
    <link rel="stylesheet" href="../qunit.css" />
    <script src="../qunit.js"></script>
    <script src="prettydate2.js"></script>
    <script>
    test("prettydate.format", function() {
        function date(then, expected) {
            equal(prettyDate.format("2008/01/28 22:25:00", then), expected);
        }
        date("2008/01/28 22:24:30", "just now");
        date("2008/01/28 22:23:30", "1 minute ago");
        date("2008/01/28 21:23:30", "1 hour ago");
        date("2008/01/27 22:23:30", "Yesterday");
        date("2008/01/26 22:23:30", "2 days ago");
        date("2007/01/26 22:23:30", undefined);
    });
 
    function domtest(name, now, first, second) {
        test(name, function() {
            var links = document.getElementById("qunit-fixture").getElementsByTagName("a");
            equal(links[0].innerHTML, "January 28th, 2008");
            equal(links[2].innerHTML, "January 27th, 2008");
            prettyDate.update(now);
            equal(links[0].innerHTML, first);
            equal(links[2].innerHTML, second);
        });
    }
    domtest("prettyDate.update", "2008-01-28T22:25:00Z", "2 hours ago", "Yesterday");
    domtest("prettyDate.update, one day later", "2008/01/29 22:25:00", "Yesterday", "2 days ago");
    </script>
</head>
<body>
    <div id="qunit"></div>
    <div id="qunit-fixture">
        <ul>
            <li class="entry" id="post57">
                <p>blah blah blah...</p>
                <small class="extra">
                    Posted <span class="time"><a href="/2008/01/blah/57/" title="2008-01-28T20:24:17Z">January 28th, 2008</a></span>
                    by <span class="author"><a href="/john/">John Resig</a></span>
                </small>
            </li>
            <li class="entry" id="post57">
                <p>blah blah blah...</p>
                <small class="extra">
                    Posted <span class="time"><a href="/2008/01/blah/57/" title="2008-01-27T22:24:17Z">January 27th, 2008</a></span>
                    by <span class="author"><a href="/john/">John Resig</a></span>
                </small>
            </li>
        </ul>
    </div>
</body>
</html>

  运行实例

 

  回到开始

  重构之前,我们之前的代码会变的很简单:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Final date examples</title>
    <script src="prettydate2.js"></script>
    <script>
    window.onload = function() {
        prettyDate.update("2008-01-28T22:25:00Z");
    };
    </script>
</head>
<body>
 
<ul>
    <li class="entry" id="post57">
        <p>blah blah blah...</p>
        <small class="extra">
            Posted <span class="time"><a href="/2008/01/blah/57/" title="2008-01-28T20:24:17Z"><span>January 28th, 2008</span></a></span>
            by <span class="author"><a href="/john/">John Resig</a></span>
        </small>
    </li>
    <-- 更多内容... -->
</ul>
 
</body>
</html>

  运行实例

 

  结论

  测试JavaScript不简单是使用测试运行器,写写测试用例。他要求你需要对代码结构作比较大的改变,以方便他能被执行单元测试。我们通过一个例子演示了如何实现特定的测试框架,也介绍了如何重构代码,以使他能使用QUnit做测试。QUnit提供了很多功能,例如支持测试异步代码,例如timeouts,ajax和事件。他的可视化测试运行器可以帮助我们debug代码,对特性测试的重新执行,并且方便我们跟踪错误信息。

 

文章来源:http://qunitjs.com/intro/

目录
相关文章
|
JavaScript 前端开发 测试技术
|
JavaScript 前端开发 机器人
|
Web App开发 JavaScript 测试技术
QUnit系列 -- 1.介绍单元测试(上)
  大家都知道单元测试对于保证代码质量的重要性,但是对客户端代码进行单元测试则要困难的多。一个比较棘手的问题是,因为JavaScript代码和后台代码或者html结合的比较紧密,他缺少真正单元的概念。例如对dom的操作,无论我们是借助jquery这样的类库,把js代码单独放在一个文件,还是直接使用内嵌代码的实现方式,都没有可以测试的单元。
1007 0
|
6月前
|
Java 测试技术 开发者
在软件开发中,测试至关重要,尤以单元测试和集成测试为然
在软件开发中,测试至关重要,尤以单元测试和集成测试为然。单元测试聚焦于Java中的类或方法等最小单元,确保其独立功能正确无误,及早发现问题。集成测试则着眼于模块间的交互,验证整体协作效能。为实现高效测试,需编写可测性强的代码,并选用JUnit等合适框架。同时,合理规划测试场景与利用Spring等工具也必不可少。遵循最佳实践,可提升测试质量,保障Java应用稳健前行。
68 1
|
3月前
|
测试技术 开发者 UED
探索软件测试的深度:从单元测试到自动化测试
【10月更文挑战第30天】在软件开发的世界中,测试是确保产品质量和用户满意度的关键步骤。本文将深入探讨软件测试的不同层次,从基本的单元测试到复杂的自动化测试,揭示它们如何共同构建一个坚实的质量保证体系。我们将通过实际代码示例,展示如何在开发过程中实施有效的测试策略,以确保软件的稳定性和可靠性。无论你是新手还是经验丰富的开发者,这篇文章都将为你提供宝贵的见解和实用技巧。
|
6月前
|
JSON Dubbo 测试技术
单元测试问题之增加JCode5插件生成的测试代码的可信度如何解决
单元测试问题之增加JCode5插件生成的测试代码的可信度如何解决
72 2
单元测试问题之增加JCode5插件生成的测试代码的可信度如何解决
|
5月前
|
IDE 测试技术 持续交付
Python自动化测试与单元测试框架:提升代码质量与效率
【9月更文挑战第3天】随着软件行业的迅速发展,代码质量和开发效率变得至关重要。本文探讨了Python在自动化及单元测试中的应用,介绍了Selenium、Appium、pytest等自动化测试框架,以及Python标准库中的unittest单元测试框架。通过详细阐述各框架的特点与使用方法,本文旨在帮助开发者掌握编写高效测试用例的技巧,提升代码质量与开发效率。同时,文章还提出了制定测试计划、持续集成与测试等实践建议,助力项目成功。
117 5
|
6月前
|
JSON 测试技术 数据格式
单元测试问题之使用JCode5插件生成测试类如何解决
单元测试问题之使用JCode5插件生成测试类如何解决
240 3
|
6月前
|
测试技术
单元测试问题之使用TestMe时利用JUnit 5的参数化测试特性如何解决
单元测试问题之使用TestMe时利用JUnit 5的参数化测试特性如何解决
97 2