• 手把手带你编写你的第一个单元测试


    相信有很多人遇到过这种情况,就是在入职公司后,开始接手公司的老项目,给公司的老项目修修改改。当我们在一个系统里边修改了很多代码时,但又不确定改动是否影响在核心逻辑时,是否会导致项目原来的功能出现bug时。我们就可以使用单元测试来帮助我们来进行测试。所以软件开发者编写单元测试,就成了很重要的事情。

    那我们为什么要编写单元测试? 单元测试的优点是什么?

    • 必要性:JavaScript 缺少类型检查,编译期间无法定位到错误,单元测试可以帮助你测试多种异常情况。(现在可以使用TypeScript来弥补类型检查的缺点)。
    • 验证功能:单元测试可以确保我们的代码正常运行,并且不出现异常输出以及副作用————这是很多bug产生的原因。
    • 防止错误再次发生:当我们发现错误时,添加单元测试来检查场景错误,可以防止代码在后期重构和优化中错误的再次发生。
    • 自动化、效率高:通过 console 虽然可以打印出内部信息来检查错误。但是这是效率十分低的操作,;每次测试都得打印一次,效率不能得到保证。通过编写测试用例,可以做到一次编写,多次自动运行,效率高。
    • 保护您的应用程序:单元测试可以检查可利用的漏洞(例如启用恶意 SQL 注入的漏洞用来检查代码的可靠性)。
    • 更利于后期代码的维护:互联网行业产品迭代速度很快,迭代后必然存在代码重构的过程,那怎么才能保证重构后代码的质量呢?有测试用例做后盾,就可以大胆的进行重构。

    编写单元测试的一些规范

    单元测试框架的使用,让我们能够快速编写和自动执行我们的测试,并且将它们集成到我们的开发和部署过程中。

    以下是一些常见编写测试的规范。

    保持单元测试的功能单一和代码简洁

    不要让你的单元测试过于复杂,本末倒置。尽量让你的单元测试代码简单明了,责任单一。

    全面的考虑函数运行的结果

    我们不仅仅要考虑函数正常运行时的情况,还要考虑函数错误运行时的情况。对代码进行单元测试,我们不仅仅要确保函数在输入正确的值时,有正确的输出,还要确保函数在输入错误参数时,运行的结果是失败的。这些对错误的检查更有利于我们预测引发错误的原因以及场景。

    拆分复杂的函数

    对功能逻辑复杂的函数,编写单元测试是十分困难的。我们要把复杂的函数拆分为相对较小的函数来进行单元测试。

    避免测试时涉及数据的请求(数据库and网络请求)

    单元测试应该是快速和轻量级的。但如果测试过程中涉及到网络数据的请求,或者对数据库的操作这就需要很长的时间来进行响应。这会使我们的单元测试变得很臃肿和重量级。但如果无法避免数据请求的话,我们一般会模拟请求结果来减轻我们的测试压力。

    如何编写单元测试

    现在我们都已经对单元测试有了一定的了解了,那我们就着手开始编写我们的第一个单元测吧!!!

    这次我将带着大家使用Mocha框架–市面上比较主流的测试框架之一。来编写我们的单元测试,虽然市面上每个框架都不同,但是他们大体是相似的。只要我们掌握了其中一种框架,其他的框架也能够很快的上手。

    在编写单元测试之前,请确保你的电脑上已经安装的Node.JS环境。因为我们的Mocha是运行在node环境下的。所以我默认你的node环境已经安装好了。

    创建一个新的项目

    首先创建了一个新的文件夹(必须是以英文命名) ,然后在文件夹里打开你的终端窗口或命令行窗口。然后输入npm init -y

    然后你的项目里面就会生成一个package.json文件

    在这里插入图片描述
    (我这里文件夹命名为UNIT-TEST)

    然后我们就可以再在我们的项目里面安装Moche框架了。在我们的终端窗口输入我们的npm install -D mocha命令(如果安装速度慢的建议用cnpm)

    然后打开我们的package.json文件,把脚本里的test命令修改成mocha

    在这里插入图片描述

    编写我们的被测试文件

    这里我们编写一个简单的红绿灯系统,来用于我们待会的单元测试。

    我们在项目中创建我们traffic,js文件以及编写我们的TrafficLight

    class TrafficLight {
    
      constructor() {
        // 对所有实例的lightIndex都赋值为0
        this.lightIndex = 0;
      }
      // 定义我们的静态函数colors,只要一调用就返回函数
      static get colors () {
        return ["green", "yellow", "red"];
      }
      get light () {
        return TrafficLight.colors[this.lightIndex];
      }
    
      next () {
        this.lightIndex++;
        // 这里故意设置了一个错误,this.lightIndex为3时是undefined
        if (this.lightIndex > TrafficLight.colors.length) {
          this.lightIndex = 0;
        }
      }
    }
    
    module.exports = TrafficLight;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    这个class由4部分组成

    TrafficLight.colors:一个关于交通灯的颜色的数组常量。

    lightIndex:一个指示当前交通灯颜色的Index的变量。

    light():一个返回当前交通灯颜色的函数。

    next():一个改变当前交通灯颜色的函数,使交通灯指向下一个颜色。

    接下来开始着手编写我们的第一个变量

    首先,在项目文件夹中创建一个名为test的文件夹。testMocha默认存放单元测试代码的文件夹。然后我们在test项目下再新建一个traffic.test.js文件来编写我们的单元测试

    接下来开始编写我们的traffic.test.js单元测试,首先导入我们的被测试的TrafficLight 模块。

    const TrafficLight = require( "../traffic" );
    
    • 1

    我们还需要在代码中使用assert模块进行测试,所以我们要导入assert模块

    const assert = require( "assert" );
    
    • 1

    Mocha中我们可以使用describe()函数来帮我们进行单元测试的分组。所以我们应该先定义一个顶层分组。

    describe( "TrafficLight", function () { 
    });
    
    • 1
    • 2

    然后我们就可以在这个分组下进行一些子功能的测试定义与分组。首先我们先定义一个对colors的测试。看colors是否和我们预期的相同。

    describe( "TrafficLight", function () { 
        describe( "colors", function () {
            //测试内容
        });
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们默认交通灯的colors只是三种颜色green、yellow、red。所以我们可以去验证它的长度是否符合我们的要求。我们需要用到Mocha框架里定义的it()函数语法。它要编写在describe()函数里。

    describe( "TrafficLight", function () {
        describe( "colors", function () {
            it( "has 3 states", function () {
                const traffic = new TrafficLight();
                assert.equal( 3, TrafficLight.colors.length );
            });
        });
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    然后我们运行一下看是否能通过测试。我们在终端窗口运行npm test,如果一切正确,Mocha 会打印出单元测试运行的结果。

    在这里插入图片描述

    运行通过,而且结构清晰

    编写更多的单元测试

    现在我们的项目已经可以正常运行我们的单元测试了,所以我们可以编写更多的测试用例。来测试我们的功能是否正常。

    首先,我们可以在colors分组中添加一个对红绿灯颜色顺序是否正确的测试。

    it( "colors are in order", function () {
        const expectedLightOrder = [ "green", "yellow", "red" ];
        const traffic = new TrafficLight();
        for( let i = 0; i < expectedLightOrder.length; i++ ) {
            assert.equal( expectedLightOrder[ i ], TrafficLight.colors[ i ] );
        }
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    我们还可以对next()函数进行测试,看他是否可能正确的改变红绿灯的颜色,使其按照正确的顺序执行。对next()的测试不应该属于color分组。所以我们应该为它新建一个分组。并且在这个分组里编写两个测试,一个是测试交通灯的颜色是否按正确的顺序改变,一个是测试交通灯是否可以正确的循环执行。

    describe( "next()", function () {
        it( "changes lights in order", function () {
            const traffic = new TrafficLight();
            for( let i = 0; i < TrafficLight.colors.length; i++ ) {
                assert.equal( traffic.light, TrafficLight.colors[ i ] );
                traffic.next();
            }
        });
        it( "loops back to green", function () {
            const traffic = new TrafficLight();
            // 颜色变化的循环顺序是 green -> yellow -> red -> green
            for( let i = 0; i < 3; i++ ) {
                traffic.next();
            }
            assert.equal( traffic.light, TrafficLight.colors[ 0 ] );
        });
    });
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在这里插入图片描述

    当我们运行单元测试时,我们可以看到有一个测试失败的提示。这因为我们在编写TrafficLight类时,故意设置的一个错误,当this.lightIndex为3时结果是undefined。无法正确循环执行从red回到green

      next () {
        this.lightIndex++;
        // 这里故意设置了一个错误,this.lightIndex为3时是undefined
        if (this.lightIndex > TrafficLight.colors.length) {
          this.lightIndex = 0;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    那么其实修改这个错误也十分简单,我们只需要把我们的>改为===,当lightIndex的值超过我们的color数组长度时,它就会自动被赋值为0,回到初始值。这样就可以使我们的代码正常执行。

    if( this.lightIndex === TrafficLight.colors.length ){ 
        this.lightIndex = 0; 
    }
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    总结

    单元测试的编写是比较简单的,它是提高我们软件开发的工具。它的使用有助于帮我更早的发现错误。并防止我们后期重构代码时再次产生同样的错误。它可以让我们的项目后期更易于管理和维护,即使我们的项目代码体积结构变得更大更复杂——尤其是在更大的开发团队中。而且自动化单元测试还能够让开发人员在够重构和优化代码时,不必担心新代码的是否会影响旧的功能。单元测试是开发过程的关键部分,对于帮助您构建更好、更安全的 JavaScript 应用程序至关重要。

  • 相关阅读:
    IBM LinuxONE Community Cloud 免费试用申请教程
    论文阅读(4) 游泳水母对被动能量再捕获的广泛利用
    混合云搭建-S2S VPN 连接Azure和AWS云动手实践
    数据分析与Excel(三)
    解决尚医通com.aliyun.oss 和com.aliyun 爆红
    Mac上使用FFmpeg
    所见即所得的3D打印建模设计
    MATLAB位运算
    软考中级-软件设计师-视频学习时长记录
    python编程难在哪里?
  • 原文地址:https://blog.csdn.net/weixin_45215308/article/details/127838095