一、背景
随着平台功能越来越多,接口及关联数据复杂,传统功能测试无法满足覆盖测试要求,顾搭建针对TypeScript的自动化单元测试。
该测试体系具有以下优点:
- 缩短测试时间:通过自动化测试体系,可以一键执行测试用例,生成测试报告以及代码覆盖率报告。开发人员可根据报告分析出问题所在,以及未测试的代码。
- 更高的投资回报率:自动化测试比传统功能测试速度更快,且测试用例可重用,避免功能开发后“关联功能”的重复测试。减少了测试以及开发时间,对快速相应要求极高的市场极为有益。
- 早期缺陷检测:编写白盒测试用例阶段,相当于做了一次代码走查,可分析出代码存在的浅显逻辑错误;白盒测试执行阶段,相当于将所有功能执行一至多遍,将代码逻辑缺陷暴露在系统测试之前。
- 更高的测试覆盖率:自动化单元测试的测试范围更全面,相较于传统测试方式,可覆盖更全面的代码逻辑以及功能逻辑,从而降低发布后的故障概率。
二、技术栈概念
Karma(卡玛)是一个基于node.js的JavaScript测试执行过程管理工具,它可以拉起所有主流浏览器,加载测试脚本,然后运行测试用例,完成后关闭浏览器。
Mocha(摩卡)是一个单元测试测试框架/库,它可以用来写测试用例。
Chai 是用于节点和浏览器的BDD / TDD断言库,可以与任何javascript测试框架完美地配对,支持BDD风格的expect、should和TDD风格的assert。
我们主要就是用Karma与Mocha来实现自动化测试。
三、技术栈的安装及使用
Node.js
Node.js是一个基于Chrome V8引擎的JavaScript运行环境,让JavaScript运行在服务端的开发平台。是部署自动化单元测试体系不可或缺的环境。
3.1下载NodeJS
NodeJS安装包及源码下载地址为:
NodeJS
根据不同的系统选择你需要的安装包。
3.2Wondows上安装NodeJS
-
双击NodeJs安装文件,将出现如下界面:
2、点击Next按钮,将出现如下界面,并勾选接受协议选项,点击Next按钮:
3、NodeJs默认安装目录为"C:\Program Files\nodejs\",如需更改安装目录,请点击Change按钮,更改完毕后点击Next按钮
4、点击属性图标来选择需要的安装模式,然后点击Next按钮,如下图:
5、点击Install开始安装NodeJS
6、安装完成后可以同命令行来检测是否安装成功以及环境变量是否配置成功:
- 同时按住Win+R键打开运行面板
- 在运行面板输入框中输入cmd并点击确定
- 在命令行界面输入path并按回车键,查看结果中是否含有你的NodeJs安装目录
- 在命令行界面输入node --version并按回车键,可以查看NodeJs版本
3.3完成NodeJS环境搭建
至此就完成了NodeJS环境的搭建了,后续就可以进行接下来的步骤了,例如:项目的创建、搭建Mocha测试框架等。
四、Mocha
mocha是一个功能丰富的JavaScript测试框架,运行在NodeJs和浏览器中。Mocha测试连续运行,允许灵活和准确的报告,同时将未补货的异常映射到正确的测试用例。
4.1安装Mocha
使用NPM全局安装也可以作为项目的依赖进行安装
//全局安装
$ npm install --global mocha
//作为项目依赖进行安装
$ npm install --save-dev mocha
或直接在项目配置文件package.json中添加相应库的依赖,例如:
"@types/mocha": "^9.1.0",
"mocha": "^9.2.2"
4.2使用Mocha
Mocha中的BBD接口提供了describe、context,it,specify,before,after,beforeEach,afterEach接口。
context接口只是一个别名describe,行为方式相同;它只是提供了一重让测试更容易阅读和组织的方法;同样,specify是别名it。
describe接口是一个描述,用来定义一个测试块,该测试块有固定的生命周期:before、after、beforeEach、afterEach以及测试用例it。
用法示例:
describe('test', function() {
// 在本测试块的所有测试用例之前执行且仅执行一次
before(function() {
});
// 在本测试块的所有测试用例之后执行且仅执行一次
after(function() {
});
// 在测试块的每个测试用例之前执行(有几个测试用例it,就执行几次)
beforeEach(function() {1
});
// 在测试块的每个测试用例之后执行(同上)
afterEach(function() {17
});
// 测试用例
it('test item1', function () {
})
});
4.3断言
mocha允许你是用任意你喜欢的断言库,若不引入其他断言库则会使用NodeJs中内置断言模块作为断言。如果能够抛出一个错误,它就能够运行。本测试体系使用chai作为断言库,详情请参照chai。
五、Chai
chai是一个BDD和TDD诊断库,可与任何JavaScript测试框架完美搭配。包含三个断言库,支持BDD风格的expect、should和TDD风格的assert。
TDD:测试驱动开发。是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。
BDD:行为驱动开发。是测试驱动开发的延伸,强调使用DLS描述用户行为,定义业务需求,是需求分析人员、开发人员与测试人员进行沟通的有效方法。行为驱动开发的核心在于“行为”,由“行为”来确定以及推动开发。
5.1安装Chai
使用NPM作为项目的依赖进行安装
$ npm install --save-dev chai
或直接在项目配置文件package.json中添加相应库的依赖后再进行安装,例如:
"@types/chai": "^4.3.0",
"chai": "^4.3.6"
5.2使用Chai
在您的代码中导入chai库,然后选择您想要使用的样式之一(assert、expect、should)
const { assert } = require('chai'); // Using Assert style
const { expect } = require('chai'); // Using Expect style
const { should } = require('chai'); // Using Should style
Chai断言库具有一定的断言规范, 本文主要使用expect断言库:
- not对之后的断言取反;
expect(foo).to.not.equal('bar');
expect(goodFn).to.not.throw(Error);
expect({ foo: 'baz'}).to.have.property('foo').and.not.equal('bar');
- deep设置deep标记,然后使用equal和property断言,该标记可以让其后的断言不是比较对象本身,而是递归比较对象的键值对;
expect(foo).to.deep.equal({ bar: 'baz'});
expect({ foo: { bar: { baz: 'quux'}}}).to.have.deep.property('foo.bar.baz', 'quux');
- a(type)/an(type)被测试的值的类型,a和an断言即可作为语言链又可作为断言使用;
// 类型断言
expect('test').to.be.a('string');
expect({ foo: 'bar' }).to.be.an('object');
expect(null).to.be.a('null');
expect(undefined).to.be.an('undefined');
expect(new Error).to.be.an('error');
expect(new Promise).to.be.a('promise');
expect(new Float32Array()).to.be.a('float32array');
expect(Symbol()).to.be.a('symbol');
// es6 overrides
expect({[Symbol.toStringTag]:()=>'foo'}).to.be.a('foo');
// language chain
expect(foo).to.be.an.instanceof(Foo);
- include(value)/contains(value)即可作为属性类断言前缀语言链又可作为作为判断数组、字符串是否包含某值的断言使用。当作为语言链使用时,常用于key()断言之前;
expect([1, 2, 3]).to.include(2);
expect('foobar').to.include('bar');
expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
- ok断言目标为真值;
expect('everything').to.be.ok;
expect(1).to.be.ok;
expect(false).to.not.be.ok;
expect(null).to.not.be.ok;
- true断言目标为true,注意,这里与ok的区别是不进行类型转换,只能为true才能通过断言;
expect(true).to.be.true;
expect(1)to.not.be.true;
-
false断言目标为false,与true相似;
expect(false).to.be.false;
expect(0).to.not.be.false;
-
null断言目标为null;
expect(null).to.be.null;
expect(undefined).to.not.be.null;
-
undefined断言目标为undefined;
expect(undefined).to.be.undefined;
expect(null).to.not.be.undefined;
-
exist断言目标存在,即非null也非undefined;
let foo = 'hi';
let bar = null;
let baz;
expect(foo).to.exist;
expect(bar).to.not.exist;
expect(baz).to.not.exist;
-
empty断言目标的长度为0。对于数组和字符串,它检查length属性,对于对象,它检查可枚举属性的数量;
expect([]).to.be.empty;
expect('').to.be.empty;
expect({}).to.be.empty;
-
equal(value)断言目标严格等于(===)value,另外,如果设置了deep标记,则断言目标深度等于value;
expect('hello').to.equal('hello');
expect(42).to.equal(42);
expect(1).to.not.equal(true);
expect({ foo: 'bar'}).to.not.equal({ foo: 'bar'});
expect({ foo: 'bar'}).to.deep.equal({foo: 'bar'});
-
above(value)断言目标大于(超过)value;
expect(10).to.be.above(5);
-
least(value)断言目标不小于(大于或等于)value;
expect(10).to.be.at.least(10);
-
below(value)断言目标小于value;
expect(5).to.be.below(10);
-
most(value)断言目标不大于(小于或等于)value;
expect(5).to.be.at.most(5);
-
within(start,finish)断言目标在某个区间内;
expect(7).to.be.within(5, 10);
-
instanceof(constructor)断言目标是构造函数constructor的一个实例
let model = new M3D.Model();
expect(model).to.be.an.instanceof(M3D.Model);
expect([1, 2, 3]).to.be.an.instanceof(Array);
-
string断言目标字符串包含另一个字符串
expect('foobar').to.have.string('bar');
在您编写完断言代码之后就希望运行这个断言,判断该断言是否正确,这时,就用到了我们的运行环境Karma库了。
六、Karma
Karma为前端自动化测试提供了跨浏览器测试的能力,它集成了像Jasmine(基于BDD的测试框架)、PhantomJs(无界面的浏览器)这些测试套件。还有一些其他又用的功能,比如生成代码覆盖率报告等。
该工具可用于测试所有主流 Web 浏览器,也可集成到 CI 工具,也可和其他代码编辑器(例如 VsCode)一起使用。这个测试工具的一个强大特性就是,它可以监控(Watch)文件的变化,然后自行执行,通过 console.log
显示测试结果。主要提供以下功能:
- 提供真实环境,可以配置各种 chrome、firefox 等各种浏览器环境或者
Phantomjs
等无头浏览器环境 - 可控制自动化测试流程,比如编辑器保存时自动全部全部测试用例
- 强大适配器,可以在
karma
上面配置jasmine
,mocha
等单元测试框架。 - 配置方便
6.1安装Karma
使用NPM作为项目的依赖进行安装
$ npm install karma -g
或直接在项目配置文件package.json中添加相应库的依赖后再进行安装,例如:
"karma": "^6.3.17"
本测试体系中使用的测试框架为Mocha,所以需添加关联库karma-mocha
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
本测试体系中使用的断言库为Chai,所以需添加关联库karma-chai
"karma-chai": "^0.1.0",
若单元测试用例语言为TypeScript,则需添加关联库karma-typescript
"karma-typescript": "^5.5.3",
若需要在谷歌浏览器运行测试用例,则需添加关联库karma-chrome-launcher
"karma-chrome-launcher": "^3.1.1",
若需要生成html的测试报告,则需要添加关联库karma-htmlfile-reporter
"karma-htmlfile-reporter": "^0.3.8",
当然代码覆盖率也同样少不了关联库,karma-coverage
"karma-coverage": "^2.2.0",
6.2配置karma
运行Karma之前需初始化:karma init
或直接使用配置文件:
// Karma 相关配置文件
//karma 的服务器将我们的服务内容放在了 / base 之下,我们在使用的时候,必须特别注意这一点。
module.exports = function (config) {
config.set({
// 基础路径,用在files,exclude属性上
basePath: '',
// 识别ts
mime: {
'text/x-typescript': ['ts', 'tsx']
},
//依赖的框架
frameworks: ['mocha', 'chai', 'karma-typescript'],
karmaTypescriptConfig: {
compilerOptions: {
module: "commonjs"
},
tsconfig: "./tsconfig.json"
},
// 需要加载到浏览器的文件列表
files: [
'TestDemo/TestDemo.ts',
'Test/TestDemo.test.ts',
],
// 排除的文件列表
exclude: [
"node_moudules",
],
// 在浏览器使用之前处理匹配的文件
preprocessors: {
'TestDemo/*.ts': ['karma-typescript', 'coverage'],
'Test/*.ts': ['karma-typescript'],
},
//点击debug按钮在debug.html中展示测试结果
client: {
mocha: {
// change Karma's debug.html to the mocha web reporter
reporter: 'html',
// require specific files after Mocha is initialized
//require: [require.resolve('bdd-lazy-var/bdd_lazy_var_global')],
// custom ui, defined in required file above
//ui: 'bdd-lazy-var/global',
//grep: ' <pattern> ',
// expose: [' body '],
//opts: ' test/mocha.opts '
}
},
// 使用测试结果报告者
reporters: ['mocha', 'html', 'coverage'],
//控制台生成mocha样式的测试结论
mochaReporter: {
output: 'autowatch'
},
//生成本地的测试报告
htmlReporter: {
outputFile: 'reporter/testResult.html',
// Optional
pageTitle: 'Reader 模块测试用例',
subPageTitle: '读取模型相关的单元测试用例类列表',
groupSuites: true,
useCompactStyle: true,
useLegacyStyle: true
},
//覆盖率
coverageReporter: {
type: 'html',
dir: 'coverage/',
file: 'coverage.html'
},
// 服务端口号
port: 9877,
// 启用或禁用输出报告或者日志中的颜色
colors: true,
// 日志等级
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// 启用或禁用自动检测文件变化进行测试
autoWatch: true,
// 测试启动的浏览器
// available browser launchers: https://www.npmjs.com/search?q=keywords:karma-launcher
browsers: ['Chrome'],
// 开启或禁用持续集成模式
// 设置为true, Karma将打开浏览器,执行测试并最后退出
singleRun: false,
// 并发级别(启动的浏览器数)
concurrency: Infinity,
})
}
具体karma配置内容,可参考官方文档:https://karma-runner.github.io/latest/config/configuration-file.html
6.3运行karma
Karma的运行命令为karma start
运行的结果首先可以在控制台详细的显示出来:
其次若配置了测试启动的浏览器,那么就会自动打开浏览器进行显示您的测试结果
点击界面上DEBUG按钮,跳转至全部测试用例界面,可以查看每个测试用例的执行情况,并且可以单独运行某一个测试用例。
配置文件中的coverageReporter
代表着代码覆盖率报告相关配置,例如:
//覆盖率
coverageReporter: {
type: 'html',//代码覆盖率报告类型
dir: 'coverage/',//代码覆盖率报告生成路径
},
- type:指一个记录类型
-
html(默认) lcov(lcov and html) lcovonly text text-summary cobertura(xml格式的支持Jenkins) teamcity json json-summary in-memory none
- dir:将用于输出代码覆盖率报告
- subdir:将用于补充dir选项来生成完整的输出目录路径。
- file:如果您使用
cobertura
、lcovonly
、teamcity
、text
、text-summary
中的一个,则需要指定输出的文件。 - check:将用于配置覆盖率结果最低阈值,如果不符合,karma将返回一个错误。阈值,指定为正数时所需的最小百分比。当一个阈值被指定为负数时,它表示允许的未覆盖实体的最大数量。
- watermarks:将用于设置覆盖阈值颜色。第一个数字是红色和黄色之间的阈值,第二个数字是黄色和绿色之间的阈值。
watermarks: {
statements: [ 50, 75 ],
functions: [ 50, 75 ],
branches: [ 50, 75 ],
lines: [ 50, 75 ]
}
七、示例
下面我们将使用两种方式配置本单元测试体系进行测试。
7.1新建项目
7.1.1创建项目
以Visual Studio为例
- 启动Visual Studio,选择 创建新项目 ;
- 选择创建TypeScript的空白Node.js应用程序;
- 填写项目名称、项目存放位置,然后点击创建。即可生成对应的项目;
-
创建成功后项目结构如下:
-
npm文件夹存放项目运行所依赖的库;
-
package.json为项目描述文件,包含项目名称、版本、入口文件等相关信息。
7.1.2添加测试库依赖
打开项目中package.json文件,在devDependencies节点添加如下引用(若有重复请删除):
具体代码如下:
"@types/node": "^14.14.7",
"typescript": "^4.0.5",
"@types/chai": "^4.3.0",
"@types/mocha": "^9.1.0",
"chai": "^4.3.6",
"karma": "^6.3.17",
"karma-chai": "^0.1.0",
"karma-chrome-launcher": "^3.1.1",
"karma-coverage": "^2.2.0",
"karma-htmlfile-reporter": "^0.3.8",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-typescript": "^5.5.3",
"mocha": "^9.2.2"
然后在项目的npm节点点击鼠标右键选择安装npm包,等待安装完成。
7.1.3添加工程文件夹以及代码文件
- 在工程中的项目名称位置点击鼠标右键,选择添加->新建文件夹,输入文件夹名称
- 在上一步骤创建的文件夹位置点击鼠标右键,选择添加->新建项,选择"TypeScript文件"
- 在上一步骤创建的TypeScript中添加demo逻辑
export class TestDemo {
/**
* @description 计算两个数值之和
* @param a 第一个数值
* @param b 第二个数值
*/
public static add(a: number, b: number): number {
if (typeof a === "number" && typeof b === "number") {
return a + b;
}
return null;
}
}
7.1.4添加测试文件夹以及测试用例
- 在工程中的项目名称位置点击鼠标右键,选择添加->新建文件夹,输入文件夹名称
- 在上一步骤创建的文件夹位置点击鼠标右键,选择添加->新建项,选择"TypeScript文件"
- 在上一步骤添加的TypeScript文件中添加单元测试用例
import { TestDemo } from "../TestDemo/TestDemo";
const { expect } = require("chai");
describe("TestDemo单元测试用例:参数为3和5", function () {
it("", function () {
let result = TestDemo.add(3, 5);
expect(result).to.equal(8);
});
});
7.1.5添加karma测试配置文件
在工程中的项目名称位置点击鼠标右键,选择添加->新建项,选择"JavaScript文件",文件名为"karma.conf.js",添加配置json并修改其中加载到浏览器的文件列表项:
files: [
'TestDemo/TestDemo.ts',
'Test/TestDemo.test.ts',
],
7.1.6运行测试用例
- 在工程中的项目名称位置点击鼠标右键,选择在终端打开:
2、执行测试用例,在终端输入"karma start"后回车
7.2.2添加测试文件夹以及测试用例
- 我的TypeScript工程M3DDemo,工程下存在代码文件src/Test.js,且存在方法如下:
var add = function (a, b) {
if (typeof a === "number" && typeof b === "number") {
return a + b;
}
return null;
}
- 创建test的测试文件夹,在我的工程中项目名称位置点击鼠标右键,选择添加->新建文件夹->输入test;
- 创建Test.test.js单元测试文件:在上一步骤创建的test文件夹位置点击鼠标右键,选择添加->新建项,选择JavaScript文件,修改文件名称后点击添加。
- 在上一步骤创建的Test.test.js中添加测试用例:
//JavaScript不能添加require
//const { expect } = require("chai");
describe("Test单元测试用例", function () {
it("add接口单元测试用例:参数为3和5", function () {
let result = add(3, 5);
expect(result).to.equal(8);
});
});
八、常见问题
8.1 karma无法运行
输入karma start运行时提示karma:无法将"karma"项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
解决方法:文章来源:https://www.toymoban.com/news/detail-426244.html
- 查看所有依赖包是否已安装完成;
- 在终端执行npm install -g karma-cli,全局安装karma-cli。
8.2 karma无法加载文件,未对karma.ps1进行数字签名
解决方法:
- 以管理员身份打开powershell;
- 执行Set-ExecutionPolicy -ExecutionPolicy UNRESTRICTED;
- 输入Y,回车。
8.3 执行karma之后未自动启动浏览器
解决方法:
- 检查是否添加配置karma.conf.js;
- 若不需要添加配置,则在浏览器中手动输入控制台输出的地址即可。
8.4 You need to include some adapter that implements _karma_.start method
解决方法:添加karma.conf.js。文章来源地址https://www.toymoban.com/news/detail-426244.html
到了这里,关于Karma、Mocha和Chai自动化测试解决方案的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!