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/

adpics.aspx?source=kbh1983&sourcesuninfo
目录
相关文章
|
JavaScript 前端开发 机器人
|
Web App开发 JavaScript 测试技术
QUnit系列 -- 1.介绍单元测试(上)
  大家都知道单元测试对于保证代码质量的重要性,但是对客户端代码进行单元测试则要困难的多。一个比较棘手的问题是,因为JavaScript代码和后台代码或者html结合的比较紧密,他缺少真正单元的概念。例如对dom的操作,无论我们是借助jquery这样的类库,把js代码单独放在一个文件,还是直接使用内嵌代码的实现方式,都没有可以测试的单元。
954 0
|
1月前
|
Java 测试技术 开发者
Java单元测试与集成测试:确保代码质量的最佳实践
【4月更文挑战第2天】在软件开发中,单元测试验证单个代码单元(如Java类或方法)的功能,确保其正确性;而集成测试则关注多个组件协作时的交互。JUnit是常见的Java单元测试框架,集成测试则检验组件间接口的兼容性。Spring框架提供了集成测试的支持。遵循良好编码习惯,编写可测试代码,设计全面的测试用例,是保证代码质量和稳定性的关键。
|
1月前
|
Java 测试技术
SpringBoot整合单元测试&&关于SpringBoot单元测试找不到Mapper和Service报java.lang.NullPointerException的错误
SpringBoot整合单元测试&&关于SpringBoot单元测试找不到Mapper和Service报java.lang.NullPointerException的错误
22 0
|
4天前
|
测试技术
测试基础 Junit单元测试框架
测试基础 Junit单元测试框架
11 2
测试基础 Junit单元测试框架
|
12天前
|
安全 测试技术 Go
Golang深入浅出之-Go语言单元测试与基准测试:testing包详解
【4月更文挑战第27天】Go语言的`testing`包是单元测试和基准测试的核心,简化了测试流程并鼓励编写高质量测试代码。本文介绍了测试文件命名规范、常用断言方法,以及如何进行基准测试。同时,讨论了测试中常见的问题,如状态干扰、并发同步、依赖外部服务和测试覆盖率低,并提出了相应的避免策略,包括使用`t.Cleanup`、`t.Parallel()`、模拟对象和检查覆盖率。良好的测试实践能提升代码质量和项目稳定性。
16 1
|
12天前
|
监控 JavaScript 前端开发
【TypeScript技术专栏】TypeScript的单元测试与集成测试
【4月更文挑战第30天】本文讨论了在TypeScript项目中实施单元测试和集成测试的重要性。单元测试专注于验证单个函数、类或模块的行为,而集成测试关注不同组件的协作。选用合适的测试框架(如Jest、Mocha),配置测试环境,编写测试用例,并利用模拟和存根进行隔离是关键。集成测试则涉及组件间的交互,需定义测试范围,设置测试数据并解决可能出现的集成问题。将这些测试整合到CI/CD流程中,能确保代码质量和快速响应变化。
|
15天前
|
IDE 测试技术 持续交付
【专栏】利用Python自动化测试与单元测试框架提升代码质量与效率
【4月更文挑战第27天】本文探讨了Python自动化测试与单元测试框架在提升代码质量与效率中的作用。Selenium、Appium用于Web和移动应用自动化测试,pytest提供强大、易扩展的测试支持。unittest是Python标准的单元测试框架,支持结构化测试用例和丰富的断言。实践中,应制定测试计划,编写高质量测试用例,实行持续集成与测试,并充分利用测试报告。这些工具和策略能有效保障代码质量和提升开发效率。
|
19天前
|
资源调度 JavaScript 测试技术
单元测试:编写和运行Vue组件的单元测试
【4月更文挑战第23天】本文探讨了为Vue组件编写单元测试的重要性,以及如何设置测试环境、编写和运行测试。通过使用Jest或Mocha作为测试框架,结合Vue Test Utils,可以独立测试组件的功能,如渲染、事件处理和状态管理。编写测试用例时,应注意覆盖各种行为,并使用断言验证组件状态。运行测试并观察结果,确保测试独立性和高覆盖率。单元测试是保证代码质量和维护性的关键,应随着项目发展持续更新测试用例。