首页 > 编程语言 >阅读周·深入浅出的Node.js | 代码测试,开发者掌握代码的行为和性能的极佳思路

阅读周·深入浅出的Node.js | 代码测试,开发者掌握代码的行为和性能的极佳思路

时间:2024-09-16 09:53:38浏览次数:8  
标签:Node function 代码 单元测试 js 测试 var requests

背景

去年下半年,我在微信书架里加入了许多技术书籍,各种类别的都有,断断续续的读了一部分。

没有计划的阅读,收效甚微。

新年伊始,我准备尝试一下其他方式,比如阅读周。每月抽出1~2个非连续周,完整阅读一本书籍。

这个“玩法”虽然常见且板正,但是有效。

已读完书籍《架构简洁之道》。

当前阅读周书籍《深入浅出的Node.js》

测试

单元测试

单元测试在软件项目中扮演着举足轻重的角色,是几种软件质量保证的方法中投入产出比最高的一种。

单元测试的意义

开发者写出来的代码是开发者自己的产品。要保证产品的质量,就应该有相应的手段去验证。对于开发者而言,单元测试就是最基本的一种方式。

编写可测试代码有以下几个原则可以遵循:

  1. 单一职责:如果一段代码承担的职责越多,为其编写单元测试的时候就要构造更多的输入数据,然后推测它的输出。
  2. 接口抽象:通过对程序代码进行接口抽象后,我们可以针对接口进行测试,而具体代码实现的变化不影响为接口编写的单元测试。
  3. 层次分离:层次分离实际上是单一职责的一种实现。在MVC结构的应用中,就是典型的层次分离模型,如果不分离各个层次,无法想象这个代码该如何切入测试。通过分层之后,可以逐层测试,逐层保证。

单元测试介绍

单元测试主要包含断言、测试框架、测试用例、测试覆盖率、mock、持续集成等几个方面,由于Node的特殊性,它还会加入异步代码测试和私有方法的测试这两个部分。

1、断言

断言就是单元测试中用来保证最小单元是否正常的检测方法,用于检查程序在运行时是否满足期望。

Node中提供了assert这个模块,用于实现断言。工作方式如下:

var assert = require('assert');
assert.equal(Math.max(1, 100), 100);

2、测试框架

测试框架用于为测试服务,它本身并不参与测试,主要用于管理测试用例和生成测试报告,提升测试用例的开发速度,提高测试用例的可维护性和可读性,以及一些周边性的工作。

推荐单元测试框架:mocha。

3、测试代码的文件组织

包规范中定义了测试代码存在于test目录中,而模块代码存在于lib目录下。

单元测试顺利运行还有个前提:在包描述文件(package.json)中添加相应模块的依赖关系。由于mocha只在运行测试时需要,所以添加到devDependencies节点即可:

"devDependencies": {
  "mocha": "*"
}

4、测试用例

一个行为或者功能需要有完善的、多方面的测试用例,一个测试用例中包含至少一个断言。示例代码如下:

describe('#indexOf()', function(){
  it('should return -1 when not present', function(){
    [1,2,3].indexOf(4).should.equal(-1);
  });

  it('should return index when present', function(){
    [1,2,3].indexOf(1).should.equal(0);
    [1,2,3].indexOf(2).should.equal(1);
    [1,2,3].indexOf(3).should.equal(2);
  });
});

5、测试覆盖率

测试覆盖率是单元测试中的一个重要指标,它能够概括性地给出整体的覆盖度,也能明确地给出统计到行的覆盖情况。

推荐工具:jscover模块。通过npm install jscover -g的方式可以安装该模块。

6、mock

mock即模拟异常,通过伪造被调用方来测试上层代码的健壮性等。

推荐:muk模块。示例代码如下:

var fs = require('fs');
  var muk = require('muk');
  beforeEach(function () {
    muk(fs, 'readFileSync', function(path, encoding) {
      throw new Error("mock readFileSync error");
    });
  });

  // it();
  // it();

  afterEach(function () {
    muk.restore();
  });

模拟时无须临时缓存正确引用,用例执行结束后调用muk.restore()恢复即可。

7、私有方法的测试

私有方法的测试是单元测试的一个难点。

只有挂载在exports或module.exports上的变量或方法才可以被外部通过require引入访问,其余方法只能在模块内部被调用和访问。

rewire模块提供了一种巧妙的方式实现对私有方法的访问。rewire的调用方式与require十分类似。对于如下的私有方法,我们获取它并为其执行测试用例非常简单:

it('limit should return success', function () {
  var lib = rewire('../lib/index.js');
  var litmit = lib.__get__('limit');
  litmit(10).should.be.equal(10);
});

工程化与自动化

Node以及第三方模块提供的方法都相对偏底层,在开发项目时,还需要一定的工具来实现工程化和自动化,以减少手工成本。

1、工程化

Node在*nix系统下可以很好地利用一些成熟工具,其中Makefile比较小巧灵活,适合用来构建工程。

开发者改动代码之后,只需通过make test和make test-cov命令即可执行复杂的单元测试和覆盖率。

2、持续集成

对于实际的项目而言,频繁地迭代是常见的状态,如何记录版本的迭代信息,还需要一个持续集成的环境。

推荐:利用travis-ci实现持续集成。

性能测试

性能测试包括负载测试、压力测试和基准测试等。

下面主要介绍基准测试,以及如何对Web应用进行网络层面的性能测试和业务指标的换算。

基准测试

基准测试要统计的就是在多少时间内执行了多少次某个方法。为了增强可比性,一般会以次数作为参照物,然后比较时间,以此来判别性能的差距。

这里介绍benchmark这个模块是如何组织基准测试的,相关代码如下:

var Benchmark = require('benchmark');

var suite = new Benchmark.Suite();

var arr = [0, 1, 2, 3, 5, 6];
suite
  .add('nativeMap', function () {
    return arr.map(callback);
  })
  .add('customMap', function () {
    var ret = [];
    for (var i = 0; i < arr.length; i++) {
      ret.push(callback(arr[i]));
    }
    return ret;
  })
  .on('cycle', function (event) {
    console.log(String(event.target));
  })
  .on('complete', function () {
    console.log('Fastest is ' + this.filter('fastest').pluck('name'));
  })
  .run();

它通过suite来组织每组测试,在测试套件中调用add()来添加被测试的代码。执行上述代码,得到的输出结果如下:

nativeMap x 1,227,341 ops/sec ±1.99% (83 runs sampled)
customMap x 7,919,649 ops/sec ±0.57% (96 runs sampled)
Fastest is customMap

压力测试

对网络接口做压力测试需要考查的几个指标有吞吐率、响应时间和并发数,这些指标反映了服务器的并发处理能力。最常用的工具是ab、siege、http_load等,下面我们通过ab工具来构造压力测试,相关代码如下:

$ ab -c 10-t 3 http://localhost:8001/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 5000 requests
Completed 10000 requests
Finished 11573 requests

Server Software:
Server Hostname:        localhost
Server Port:            8001

Document Path:          /
Document Length:        10240 bytes

Concurrency Level:      10
Time taken for tests:   3.000 seconds
Complete requests:      11573
Failed requests:        0
Write errors:           0
Total transferred:      119375495 bytes
HTML transferred:       118507520 bytes
Requests per second:    3857.60 [#/sec] (mean)
Time per request:       2.592 [ms] (mean)
Time per request:       0.259 [ms] (mean, across all concurrent requests)
Transfer rate:          38858.59 [Kbytes/sec] received

Connection Times (ms)
          min  mean[+/-sd] median   max
Connect:        0    0   0.3      0      31
Processing:     1    2   1.9      2      35
Waiting:        0    2   1.9      2      35
Total:          1    3   2.0      2      35

Percentage of the requests served within a certain time (ms)
50%      2
66%      3
75%      3
80%      3
90%      3
95%      3
98%      5
99%      6
100%     35 (longest request)

介绍一下各个参数的含义:

  • Document Path:表示文档的路径,此处为/。
  • Document Length:表示文档的长度,就是报文的大小,这里有10KB。
  • Concurrency Level:并发级别,就是我们在命令中传入的c,此处为10,即10个并发。
  • Time taken for tests:表示完成所有测试所花费的时间,它与命令行中传入的t选项有细微出入。
  • Complete requests:表示在这次测试中一共完成多少次请求。
  • Failed requests:表示其中产生失败的请求数,这次测试中没有失败的请求。
  • Write errors:表示在写入过程中出现的错误次数(连接断开导致的)。
  • Total transferred:表示所有的报文大小。
  • HTML transferred:表示仅HTTP报文的正文大小,它比上一个值小。
  • Requests per second:这是我们重点关注的一个值,它表示服务器每秒能处理多少请求,是重点反映服务器并发能力的指标。
  • Transfer rate:表示传输率,等于传输的大小除以传输时间,这个值受网卡的带宽限制。
  • Connection Times:连接时间,它包括客户端向服务器端建立连接、服务器端处理请求、等待报文响应的过程。

基准测试驱动开发

基准测试驱动开发,简称BDD,主要分为以下几个步骤:

(1) 写基准测试。

(2) 写/改代码。

(3) 收集数据。

(4) 找出问题。

(5)回到第(2)步。

阅读周·深入浅出的Node.js | 代码测试,开发者掌握代码的行为和性能的极佳思路_单元测试

测试数据与业务数据的转换

通常,在进行实际的功能开发之前,我们需要评估业务量,以便功能开发完成后能够胜任实际的在线业务量。

如果用户量只有几个,每天的PV只有几十个,那么网站开发几乎不需要什么优化就能胜任。

如果PV上10万甚至百万、千万,就需要运用性能测试来验证是否能够满足实际业务需求,如果不满足,就要运用各种优化手段提升服务能力。

总结

我们来总结一下本篇的主要内容:

  • 测试是应用或者系统最重要的质量保证手段。有单元测试实践的项目,必然对代码的粒度和层次都掌握得较好。
  • 单元测试能够保证项目每个局部的正确性,也能够在项目迭代过程中很好地监督和反馈迭代质量。
  • 对于性能,在编码过程中一定存在部分感性认知,与实际情况有部分偏差,而性能测试则能很好地斧正这种差异。

作者介绍非职业「传道授业解惑」的开发者叶一一。《趣学前端》、《CSS畅想》等系列作者。华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。如果看完文章有所收获,欢迎点赞

标签:Node,function,代码,单元测试,js,测试,var,requests
From: https://blog.51cto.com/u_15838863/12030042

相关文章

  • ICM20948 DMP代码详解(24)
    接前一篇文章:ICM20948DMP代码详解(23) 上一回解析完了inv_icm20948_set_lowpower_or_highperformance函数,本回回到inv_icm20948_initialize_lower_driver函数中,继续往下解析。为了便于理解和回顾,再次贴出inv_icm20948_initialize_lower_driver函数源码,在EMD-Core\sources\Inv......
  • ICM20948 DMP代码详解(23)
    接前一篇文章:ICM20948DMP代码详解(22) 上一回解析完了inv_icm20948_wakeup_mems函数,本回回到inv_icm20948_initialize_lower_driver函数中,继续往下解析。为了便于理解和回顾,再次贴出inv_icm20948_initialize_lower_driver函数源码,在EMD-Core\sources\Invn\Devices\Drivers\IC......
  • vue(utils.js工具类)常用的公共方法的整理
    /**验证手机号是否合格*true--说明合格*/exportfunctionisPhone(phoneStr){letmyreg=/^[1][3,4,5,7,8,9][0-9]{9}$/;if(!myreg.test(phoneStr)){returnfalse;}else{returntrue;}}/**验证身份证号是否合格*true--说明合格......
  • zblogphp调用当前日期/当前时间代码汇总
    有的朋友在使用zblogphp程序中会遇到想调用当前时间,官方wiki里面这个标签没有写。本文来汇总下zblogphp调用当前时间的代码。首先zblogphp使用的是php语言,所以php怎么调用的zblogphp也可以直接拿来主义,但是标签格式得改改。废话不多说,zblog的调用标签是{date("Y-m-dH:i:s")},调......
  • 走进低代码表单开发(三):高效业务功能构建
    前面我们已经介绍了勤研低代码开发平台的页面设计相关的内容,当页面设计完成后,我们将继续进行表单的功能开发,接下来,我们一起走进勤研低代码开发平台高效便捷的表单功能设计,来看看勤研低代码平台如何为用户带来全新的开发体验。一、可视化布局与事件定义勤研低代码开......
  • kettle从入门到精通 第八十五课 ETL之kettle kettle中javascript步骤调用外部javascri
     场景:交流学习群里面有小伙伴咨询kettle中的javascript代码步骤如何调用外部js文件中的函数,觉得有点意思的,于是就抽时间整理了一下。 1、外部js文件为test.js,代码如下:functiontest(param){return"接收到了参数"+param;}2、当时没有过多考虑,在本地简单写了个demo测......
  • 基于PHP的考研真题资料互助交流平台vue.js【开题实训报告源码论文】
      博主介绍:......
  • 基于PHP的网上订餐平台系统vue.js【开题实训报告源码论文】
      博主介绍:......
  • 基于Node.js+vue基于开源工作流的自来水业扩报装系统(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着城市化进程的加速和居民生活质量的提升,自来水业作为城市基础设施的重要组成部分,其服务质量与效率直接关系到民众的生活品质与城市的发展速度。然而,传统......
  • 基于Node.js+vue智慧医疗系统(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着科技的飞速发展,医疗领域正经历着前所未有的变革。传统医疗模式在面对日益增长的医疗需求、资源分配不均以及患者个性化服务要求时显得力不从心。智慧医......