美文网首页JavaScript 基础与提高
JavaScript 忍者秘籍笔记——利用测试和调试武装自己

JavaScript 忍者秘籍笔记——利用测试和调试武装自己

作者: soojade | 来源:发表于2017-02-06 16:32 被阅读23次

    第二章 利用测试和调试武装自己

    调试代码

    调试 javascript 有两个重要的方法:日志记录和断点

    日志记录

    使用console.log()方法,在控制台查看日志消息。

    断点

    可以在断点处随意查看任意代码的状态,包括:所有可访问的变量、上下文以及作用域链。

    测试用例生成

    优秀的测试用例具有三个重要特征:

    • 可重复性(repeatability)——测试结果应该是高度可再生的。多次运行测试应该产生相同的结果。
    • 简单性(simplicity)——测试应该只专注于测试一件事。在不影响测试用例目的的情况下,应尽可能消除过多的HTML标记、CSS或JavaScript。
    • 独立性(independence)——测试用例应该独立执行。避免一个测试结果依赖于另一个测试结果。

    构建测试的主要方法分别是:

    • 解构型测试:在消弱代码隔离问题时进行创建,以消除任何不恰当的问题。
    • 构建型测试:从一个大家熟知的良好精简场景开始,构建用例,直到能够重现bug为止。

    测试框架

    根据测试需要,可以从javascript测试框架中找到很多功能,包括:

    • 能够模拟浏览器行为(单击按键等)。
    • 测试的交互式控制(暂停和恢复测试)。
    • 处理异步测试超时问题。
    • 能够过滤哪些会被执行的测试。

    测试套件基础知识

    测试套件的主要目的是聚合代码中的所有单个测试,将其组合成为一个单位,这样就可以批量运行,提供一个可以轻松反复运行的单一资源。

    断言

    单元测试框架的核心是断言方法,通常叫assert()。该方法接收一个值——需要断言的值,以及一个表示该断言目的的描述。如果该值结果为true则断言通过,否则,断言失败。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>断言的简单实现</title>
        <style>
            /*定义结果样式*/
            li.pass{color: green;}
            li.fail{color: red;}
        </style>
    </head>
    <body>
        <!--显示测试结果-->
        <ul id="results"></ul>
    
        <script>
            // 定义assert方法
            function assert(value,desc){
                var li = document.createElement('li');
                li.className = value ? "pass" : "fail";
                li.appendChild(document.createTextNode(desc));
                document.getElementById("results").appendChild(li);
            }
    
            // 使用断言执行测试
            window.onload = function() {
                assert(true, "测试running...");
                assert(false, "失败!");
            }
        </script>
    </body>
    </html>
    

    测试组

    执行单元测试时,一个测试组可能代表一组断言,因为它们在我们的API或程序里关联的是一个单一的方法。如果做行为驱动开发,测试组将通过任务集成断言。在实践中动态控制层级被证明是非常有用的(如果测试失败的话,可以收缩/展开测试组,并且过滤测试)。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>测试分组的实现</title>
        <style>
            li.pass{color: green;}
            li.fail{color: red;}
        </style>
    </head>
    <body>
        <ul id="results"></ul>
    
        <script>
            (function(){
                var results;
    
                this.assert = function assert(value,desc){
                    var li = document.createElement('li');
                    li.className = value ? "pass" : "fail";
                    li.appendChild(document.createTextNode(desc));
                    results.appendChild(li);
                    if(!value){
                        li.parentNode.parentNode.className = "fail";
                    }
                    return li;
                };
    
                this.test = function test(name,fn){
                    results = document.getElementById("results");
                    results = assert(true,name).appendChild(document.createElement("ul"));
                    fn();
                };
            })();
    
            window.onload = function (){
                test("A test", function(){
                    assert(true, "First assertion completed");
                    assert(true, "Second assertion completed");
                    assert(true, "Third assertion completed");
                });
    
                test("Another test", function(){
                    assert(true, "First assertion completed");
                    assert(false, "Second assertion failed");
                    assert(true, "Third assertion completed");
                });
    
                test("A third test", function(){
                    assert(null, "fail");
                    assert(5, "pass");
                })
            }
        </script>
    </body>
    </html>
    

    异步测试

    处理该问题的方式通常是过度设计,并且设计的要比实际需要的更复杂。处理异步测试,需要遵循的简单步骤:

    1. 将依赖相同异步操作的断言组合成一个统一的测试组。
    2. 每个测试组需要放在一个队列上,在先前其他的测试组完成运行之后再运行。
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>简单的异步测试套件</title>
        <style>
            li.pass{color: green;}
            li.fail{color: red;}
        </style>
    </head>
    <body>
        <ul id="results"></ul>
    
        <script>
            (function(){
                var queue = [], paused = false, results;
    
                // test 接收一个包含多个断言的函数,这些断言可以是同步的,也可以是异步的——并放置在队列中等待执行
                this.test = function(name,fn){
                    queue.push(function(){
                        results = document.getElementById("results");
                        results = assert(true,name).appendChild(
                            document.createElement("ul"));
                            fn();
                    });
                    runTest();
                };
    
                // pause 应该在test内部调用,告诉该测试套件暂停执行测试,直到测试组完成
                this.pause = function(){
                    paused = true;
                };
    
                // resume 恢复测试,经过延迟后开始下一个测试的运行,避免出现长时间运行的代码块
                this.resume = function(){
                    paused = false;
                    setTimeout(runTest,1);
                };
    
                // 在测试排队时从队列中移除时进行调用。用于检查当前套件目前是否没被暂停以及队列中是否有测试任务,一旦满足情况,将从队列中取出一个测试并尝试执行它
                // 测试组完成执行后,runTest 会检查该套件目前是否暂停了,如果没暂停(这意味着,测试组中只有异步测试),runTest 将开始执行下一组测试
                function runTest(){
                    if(!paused && queue.length){
                        queue.shift()();
                        if(!paused){
                            resume();
                        }
                    }
                }
    
                this.assert = function assert(value,desc){
                    var li = document.createElement("li");
                    li.className = value ? "pass" : "fail";
                    li.appendChild(document.createTextNode(desc));
                    results.appendChild(li);
                    if(!value){
                        li.parentNode.parentNode.className = "fail";
                    }
                    return li;
                };
            })();
    
            window.onload = function(){
                test("Async Test #1", function(){
                    pause();
                    setTimeout(function(){
                        assert(true, "First test completed");
                        resume();
                    },1000);
                });
    
                test("Async Test #2", function(){
                    pause();
                    setTimeout(function(){
                        assert(true, "Second test completed");
                        resume();
                    },1000);
                });
            }
        </script>
    </body>
    </html>
    

    相关文章

      网友评论

        本文标题:JavaScript 忍者秘籍笔记——利用测试和调试武装自己

        本文链接:https://www.haomeiwen.com/subject/tsruittx.html