Javascript学习-简单测试环境

在《JavaScript忍者秘籍》2.4测试条件基础知识中,作者给出了一个精简版的assert和assert组的实现,对于初学者而言,这无疑是一个很好的例子,既让我们得到了一个好用的小工具,又让我们看到了用javascript实现这个工具是如此的简单。

这里主要是从代码角度最2.4章节做一些补充和说明,包括原有代码中的一些bug及其修正。当然了,既然涉及到了代码解析,这就不能说是初学者的范畴了,至少要多javascript中的函数声明,函数实现,函数闭包等内容有了基本的了解后,才能看懂这篇文章。

1.assert

先来说说assert,应用代码是这个样子的:

        <script type="text/javascript">
            assert(1 + 1 === 2, "1 + 1 = 2");
            assert(1 + 1 === 3, "1 + 1 = 3");
        </script>

assert就是一个javascript函数,有两个参数,第一个参数用来判断表达式是true或false,第二个参数用来对测试做一些说明,测试结果直接显示在html中,这里的测试结果是这个样子的:

还挺酷的吧。好了,那么我们就来看看如何实现这个assert?

首先新建一个html文件

然后在body中加入一个id为rusults的ul节点:


1

2

3

<body>

    <ul id="results"></ul>

</body>

后面所有的assert结果列表都要加到这个节点下。

assert执行完成后的html结果是这样的:

看起来挺简单的吧,就是在ul节点下对每个assert测试用li节点来表现。对于测试为true的li节点的class被赋值为pass,对于测试为false的li节点的class被赋值为fail。

原理清楚了,那么这个assert函数的代码看起来就不复杂了:

            function assert(value, desc) {
                // 创建li节点
                var li = document.createElement("li");
                // 如果value为true,li的class为pass
                // 如果value为false,li的class为fail
                li.className = value ? "pass" : "fail";
                // 根据desc创建text节点,然后添加到li节点下
                li.appendChild(document.createTextNode(desc));
                // 找到document中id为results的节点元素,就是那个body下的ul,
                // 然后把新建的li节点添加到ul节点下
                document.getElementById("results").appendChild(li);
            }

剩下的就是添加一些css,美化一下html了,既然已经学习javascript了,一般的html和css的内容就不在这说了,完整的html如下:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>assert</title>
        <style>
            body {
                font-family: sans-serif;
                font-size: 12pt;
            }

            #results {
                background-color: #e0e0e0;
                border-radius: 1em;
                padding: 1em;
                list-style-position: inside;
            }

            ul {
                list-style-type : circle;
            }

            #results li {
                margin-bottom: 0.2em;
            }

            #results li.fail {
                color: red;
                text-decoration: line-through;
            }

            #results li.pass {
                color: green;
            }
        </style>
        <script type="text/javascript">
            function assert(value, desc) {
                // 创建li节点
                var li = document.createElement("li");
                // 如果value为true,li的class为pass
                // 如果value为false,li的class为fail
                li.className = value ? "pass" : "fail";
                // 根据desc创建text节点,然后添加到li节点下
                li.appendChild(document.createTextNode(desc));
                // 找到document中id为results的节点元素,就是那个body下的ul,
                // 然后把新建的li节点添加到ul节点下
                document.getElementById("results").appendChild(li);
            }
        </script>
    </head>
    <body>
        <ul id="results"></ul>

        <script type="text/javascript">
            assert(1 + 1 === 2, "1 + 1 = 2");
            assert(1 + 1 === 3, "1 + 1 = 3");
        </script>
    </body>
</html>

2.asserts

asserts代表一个测试组,应用代码是这个样子的:

        <script type="text/javascript">
            asserts();

            test("数值计算测试", function() {
                assert(1 + 1 === 2, "1 + 1 = 2");
            });

            test("字符串测试", function() {
                assert("a" + "b" === "ab", ‘"a" + "b" = "ab"‘);
                assert("a" + "b" === "abc", ‘"a" + "b" = "abc"‘);
            });
        </script>

这段代码是说,先创建一个描述为“数值计算测试”的测试组,里面加一组assert;再创建一个描述为“字符串测试”的测试组,里面加一组assert。两个测试组之间是平级的关系。

每个测试组里的一组assert都是不同的,因此需要一个function包装起来。这个函数可以叫做“测试组assert组装函数”。

这里的测试结果是这个样子的:

看起来更酷了吧。你注意到了没有,这里有一个需求点:如果测试组里面有一个assert测试为false,那么整个测试组也要标记为false。

这个html的结构如下:

每个测试组用li节点表现,而li节点下又内嵌了一个ul节点,在这个内嵌的ul节点下才是测试组内所有assert的li节点表现。

当然了,有图有真相,这里很明显有一个小bug,"a" + "b" === "ab"明明是正确的,怎么显示的li节点也被画红线了?或许你也可以辩解为既然是整个测试组失败了,那么为这个正确的li节点画红线也说得过去吧?谁让它属于失败的测试组呢?既然选择了猪一样的队友,那就得认命。可是那你又怎么解释这个正确的li节点被一边画了红线,一边却显示为绿色的文字?这明显自相矛盾嘛。

好了,先不理这个小bug了,稍后我们会解决这个bug。现在还是让我们老老实实的来看看这个测试组的功能是如何实现的吧?

html相关的部分都不改,body里还是那个孤零零的id为rusults的ul节点,css也完全不用动,需要修改的只有javascript代码。

注意测试组的代码中先调用了一个asserts函数,这个函数负责初始化测试组的一些环境,简单的说它是这个样子的:

            // 测试组的整体初始化
            function asserts() {
                // 声明一个results变量,
                // 作为assert函数闭包和test函数闭包的一部分
                var results;

                // 创建assert表现节点
                assert = function(value, desc) {
                }

                // 创建测试组表现节点
                test = function(name, fn) {
                }
            }

这里这里对assert重新进行了赋值,当然我们首先需要知道这种assert之前没有var声明的,说明这个变量已经在全局的window中,或者将在这句代码执行处被加入到了全局的window中,而我们上面在说单个assert的时候不是已经有了一个assert函数的实现了吗?那个assert也是在全局的window中的。毫无疑问,在调用asserts函数后,原有的assert函数就被覆盖掉了。test变量也是类似的,在调用asserts函数后,将被加入到全局的window中。

注意asserts函数开始的那个results变量,因为asserts函数调用后会在全局的window增加两个函数assert和test,而这个results变量就必然的成为了这两个函数闭包的一部分。

我们先看看这个test函数是如何实现的:

                test = function(name, fn) {
                    // 找到document中id为results的ul节点元素,就是那个body下的ul
                    results = document.getElementById("results");
                    // 创建一个ul节点
                    var ul = document.createElement("ul");
                    // 创建一个测试组节点,就象创建普通assert节点一样直接调用assert
                    // 毫无意外,这个测试组节点被加到了id为results的ul节点元素下,
                    // 初始默认这个测试组节点的测试结果是true。
                    // 在测试组节点下添加内嵌的ul节点,该测试组下的所有assert表现节点都会被
                    // 加入到这个内嵌的ul节点中。
                    // 既然如此,那么我们就让results变量指向这个内嵌的ul节点
                    results = assert(true, name).appendChild(ul);

                    // 调用"测试组assert组装函数",构建各个assert表现节点
                    fn();
                };

在test函数执行的开始,results被指向了body下的ul节点,并在此基础上完成了测试组表现节点的创建,然后results被指向了测试组内嵌的ul节点上,"测试组assert组装函数"被调用,新的assert表现节点就会被加入到results节点下。

下面我们来看看新的assert函数是如何实现的:

                assert = function(value, desc) {
                    // 创建li节点
                    var li = document.createElement("li");
                    // 如果value为true,li的class为pass
                    // 如果value为false,li的class为fail
                    li.className = value ? "pass" : "fail";
                    // 根据desc创建text节点,然后添加到li节点下
                    li.appendChild(document.createTextNode(desc));
                    // 把新建的li节点添加到results下,至于这个rusults是啥?
                    // 在test执行前是body下的ul节点
                    // 在test执行后是测试组表现节点下的ul节点
                    results.appendChild(li);

                    if (!value) {
                        // 如果有一个assert测试结果是false,
                        // 那么就找到li节点的父节点的父节点,
                        // 也就是测试组表现节点了,然后设置class为fail
                        li.parentNode.parentNode.className = "fail";
                    }

                    // 返回li节点
                    // 在test执行前是测试组表现节点
                    // 在test执行后是assert表现节点
                    return li;
                };

好了,搞定,完整的html如下:

 

3.修正测试组为false的bug

之所以有这个bug,是因为这里的测试组表现太简单了,直接在li节点上设置class,使得css的可控性不高。学过css列表部分的应该都清楚,对列表的控制应该使用行内文本span嘛。

我们希望的显示效果应该是:

相应的html结构应该是:

既然只是将测试组表现节点和测试表现节点多加一层span,那么test函数是完全不用变的,只是assert函数需要做一点小的修改:

                assert = function(value, desc) {
                    // 创建li节点
                    var li = document.createElement("li");
                    // 创建sapn节点
                    var span = document.createElement("span");
                    // 根据desc创建text节点
                    var text = document.createTextNode(desc);

                    // 在li下添加span节点
                    li.appendChild(span);
                    // 在span下添加text节点
                    // 完成li>span>text的三层关系
                    span.append(text);

                    // 如果value为true,span的class为pass
                    // 如果value为false,span的class为fail
                    span.className = value ? "pass" : "fail";

                    // 把新建的li节点添加到results下,至于这个rusults是啥?
                    // 在test执行前是body下的ul节点
                    // 在test执行后是测试组表现节点下的ul节点
                    results.appendChild(li);

                    if (!value) {
                        // 如果有一个assert测试结果是false,
                        // 那么就找到li节点的父节点的父节点,
                        // 也就是测试组表现节点了
                        var liGroup = li.parentNode.parentNode;
                        // 不能直接在测试组表现节点设置class了
                        // 必须在测试组表现节点下的span节点设置class
                        // 也就是测试组表现节点下的第一个子元素
                        liGroup.childNodes[0].className = "fail";
                    }

                    // 返回li节点
                    // 在test执行前是测试组表现节点
                    // 在test执行后是assert表现节点
                    return li;
                };

相应的css也是需要做些小的修改的,不是直接在li节点上做效果了,而是在span节点上做效果。这些小地方都很容易理解,那么就直接上修改后的完整html吧:

 

时间: 2024-08-28 22:13:05

Javascript学习-简单测试环境的相关文章

iOSIPV6简单测试环境搭建

应苹果官方要求,iOS应用必须适配IPV6才能通过审核,这里分享一个简单的ipv6测试方法 一.工具原料 1.1 Mac电脑一台 1.2 iPhone手机两部 1.3 数据线一根 二.步骤方法 2.1 通过数据线将手机和电脑链接 2.2 打开手机的个人热点分享并选择仅USB 2.3 打开网络偏好设置,确保你的Mac的Wi-Fi是打开的,并且没有连接任何网络,如果已有连接wifi可以在高级里删除之前的联网缓存 2.4 打开系统偏好设置,按住option(alt)键点击共享,如果不按住option键

Linux测试环境搭建的学习建议

随着Linux应用的扩展许多朋友开始接触Linux,根据学习Windwos的经验往往有一些茫然的感觉:不知从何处开始学起.这里介绍学习Linux测试环境搭建的一些建议. 一.Linux测试环境搭建从基础开始 常常有些朋友在Linux论坛问一些问题,不过,其中大多数的问题都是很基础的.例如:为什么我使用一个命令的时候,系统告诉我找不到该目录,我要如何限制使用者的权限等问题,这些问题其实都不是很难的,只要了解了 Linux 的基础之后,应该就可以很轻易的解决掉这方面的问题.而有些朋友们常常一接触Li

JavaScript学习指南。

JavaScript - 客户端脚本语言 JavaScript是属于网络的脚本语言! JavaScript被数百万计的网页用来改进设计.验证表单.检测浏览器的一系列以及更多的应用. JavaScript学习简单. 什么是JavaScript,可以做什么 JavaScript为HTML设计师提供了一种编程工具 HTML 创作者往往都不是程序员,但是 JavaScript 却是一种只拥有极其简单的语法的脚本语言!几乎每个人都有能力将短小的代码片断放入他们的 HTML 页面当中. JavaScript

简单搭建环境,测试Android应用

如果你编写完Android应用软件,要进行一个测试,可以学习这个方法,具体内容如下所示: 用Eclipse建立测试 首先搭建测试环境: 下载安装Eclipse ADT插件 导入或创建我们想要测试的Android应用项目. 生成一个对应于应用程序项目测试的测试项目.为导入项目生成一个测试项目: a.在项目浏览器里,右击我们的应用项目,然后选择Android Tools > New Test Project b.在新建Android测试项目面板,为我们的测试项目设置合适的参数,然后点击Finish

FastDfs 学习进阶之环境安装及上传文件测试

一:环境介绍       10.63.13.138 tracker,nginx proxy 10.63.13.143 storage,nginx 二:资源包准备 FastDFS官方论坛:http://www.csource.org 资源下载路径:http://sourceforge.net/projects/fastdfs/files/ 本实验学习环境使用CENTOS 6.4 X64 需要下载的资源包: FastDFS源代码:FastDFS_v5.05.tar.gz nginx模块源代码:fas

[软件测试]Linux环境中简单清爽的Google Test (GTest)测试环境搭建(初级使用)

本文将介绍单元测试工具google test(GTEST)在linux操作系统中测试环境的搭建方法.本文属于google test使用的基础教程.在linux中使用google test之前,需要对如下知识有一些了解: (1)C/C++编程方法 (2)makefile的编写 (3)linux命令行操作 (4)GTEST背景知识:它是用来干什么的?它用什么语言编写的?它的一些基本语法?等等 以上知识不需要做到熟能生巧,只要达到入门级别,使用GTEST不会费任何力气,毕竟GTEST也不是一个高门槛的

在vSphere环境下简单测试Windows 2016 S2D (2)

在了解了S2D基本概念及架构以后,我们接下来做一些具体的配置及测试.本实验环境搭在vCenter6.0u2上,配置四台虚机作为S2D的节点,每台虚机的具体配置如下: OS:Windows 2016 datacenter 4 vCPU& 8GB RAM 4 vNics 1个40GB磁盘装OS:另外再添加2 x 50GB(模拟PCIe SSD):2 x 100GB(模拟SSD):4 x 300GB(HDD) 本测试的设想是将模拟的NVMe PCIe SSD磁盘作为读写缓存使用,而把SSD和HDD作为

在vSphere环境下简单测试Windows 2016 S2D (3)

W2016包含了很多Powershell工具,帮助用户诊断.查看和收集存储相关的日志.在接下来的实验里,我们一起看看和排错相关的命令. 用Get-StorageSubSystem命令查看测试环境里的S2D子系统的名称,比如下面这个是笔者测试用的S2D,因为名字较长,所以后续步骤命令中均以通配符"*"取代除"cluster"之外的部分: 2. Enable-StorageDiagnosticLog 命令能够配置收集不同级别的日志信息(包含Critical.Error.

mysql学习之旅-数据库自动备份-测试环境搭建

#终于知道什么叫不会走先会跑了,刚开始接触第一个case就是数据库自动备份,我可是都没安装过啊?!   发完牢骚开始干活 首先,因为业务已经上线,不能随便动,先搭建测试环境吧 规划一下 版本:mysql-5.7.14-winx64.zip  从官网下载 系统:windows 7   64bit 解压缩到本地目录 D:\app\mysql57    #注意,非系统盘,非中文 将my-default.ini 复制一份重命名为my.ini  添加如下内容,先保证能开启服务 # For advice o