首先需要安装相应的包:npm i -D jest ts-jest supertest jest-express jest-sonar-reporter sonarqube-scanner
1、单元测试:npm run test
2、代码覆盖率:npm run test:cov
3、使用SonarQube平台分析:npm run sonar,完成后就可以使用SonarQube web查看相关数据
4、如何调试单元测试的代码,有二种方法:1、在vscode终端运行npm run test:debug,2、在vscode的launch.json中添加相应的代码,然后就右直接选择运行中的Debug Jest Tests来启动
在pageage.json增加如下配置
1 "scripts": {
2 "lint": "eslint 'src/**/*.{ts,js}'",
3 "lint:fix": "eslint 'src/**/*.{ts,js}' --fix",
4 "lint:ts": "tslint -p tsconfig.json -c tslint.json",
5 "test": "jest --runInBand --forceExit --colors",
6 "test:watch": "jest --watch",
7 "test:cov": "jest --coverage",
8 "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
9 "test:e2e": "jest --runInBand --config ./test/jest-e2e.json",
10 "sonar": "node sonar-project.js"
11 },
12 "engines": {
13 "node": ">=8.9.0"
14 },
15 "jest": {
16 "moduleFileExtensions": [
17 "js",
18 "json",
19 "ts"
20 ],
21 "moduleNameMapper": {
22 "^@creative(.*)$": "<rootDir>/modules/creative$1",
23 "^@admin(.*)$": "<rootDir>/modules/admin$1",
24 "^@configuration(.*)$": "<rootDir>/modules/configuration$1",
25 "^@common(.*)$": "<rootDir>/common$1",
26 "^@auth(.*)$": "<rootDir>/modules/auth$1"
27 },
28 "rootDir": "src",
29 "testRegex": ".spec.ts$",
30 "transform": {
31 "^.+\\.(t|j)s$": "ts-jest"
32 },
33 "collectCoverageFrom": [
34 "**/*.(t|j)s"
35 ],
36 "testResultsProcessor": "jest-sonar-reporter",
37 "coverageDirectory": "../coverage",
38 "coveragePathIgnorePatterns": [
39 "/node_modules/"
40 ],
41 "testEnvironment": "node"
42 },
43 "jestSonar": {
44 "reportPath": "coverage",
45 "reportFile": "test-reporter.xml",
46 "indent": 4
47 }
sonar-project.js
const sonarqubeScanner = require('sonarqube-scanner');
const parameters = {
serverUrl: 'http://localhost:9000',
token: 'XXX',
options : {
'sonar.projectVersion': '1.1',
'sonar.projectName': 'create-server',
'sonar.projectKey': 'create-server',
'sonar.sourceEncoding': 'UTF-8',
'sonar.scm.provider': 'git',
'sonar.language': 'typescript',
'sonar.sources': 'src',
'sonar.inclusions': 'src/**',
'sonar.exclusions': '**/node_modules/**,**/coverage/**',
'sonar.tests': 'test',
'sonar.ts.tslint.configPath': 'tslint.json',
'sonar.test.inclusions': 'src/**/*.spec.ts,test/**/*.e2e-spec.ts',
'sonar.testExecutionReportPaths': 'coverage/test-reporter.xml',
'sonar.javascript.lcov.reportPaths': 'coverage/lcov.info',
}
}
sonarqubeScanner(parameters, () => process.exit());
示例代码
1 import { Test, TestingModule } from '@nestjs/testing';
2 import { AppController } from './app.controller';
3 import { AppService } from './app.service';
4 import { ApplicationModule } from './app.module';
5 import { Request } from 'jest-express/lib/request';
6 import { Response } from 'jest-express/lib/response';
7
8 describe('AppController', () => {
9 let appController: AppController, appService: AppService, req: Request, res: Response;
10
11 beforeAll(async () => {
12 const module: TestingModule = await Test.createTestingModule({
13 imports: [ApplicationModule],
14 }).compile();
15
16 appController = module.get<AppController>(AppController);
17 appService = module.get<AppService>(AppService);
18 req = new Request();
19 res = new Response();
20 });
21
22 describe('controller test', () => {
23 it('Mock一个函数返回动态测试数据', () => {
24 expect.assertions(1);
25
26 // 通过jest.fn()来Mock一个回调函数返回测试数据
27 const mockfn = jest.fn();
28 const result = mockfn.mockReturnValue(`[${new Date()}]: Welcome to use youtu test service.`);
29
30 // 调用Controller的root方法,root方法调用service里的root方法返回相应的结果与mock结果是否达到预期
31 expect(appController.root()).toBe(result());
32 });
33
34 it('监听函数是否被正常调用', async (done) => {
35 // 验证第二个断言被调用,测试异步代码时这通常很有用
36 expect.assertions(3);
37 const spyfn = jest.spyOn(appService, 'getAllUsers');
38 req.setBody({ name: 'mock data' });
39 expect(await appController.getAllUsers(req, res)).toBe('test service');
40 // 用来判断一个函数是否被调用过
41 expect(spyfn).toHaveBeenCalled();
42
43 // 判断函数被调用过几次
44 expect(spyfn).toHaveBeenCalledTimes(1);
45 done();
46 });
47
48 it('Mock函数调用', async (done) => {
49 // 验证第二个断言被调用,测试异步代码时这通常很有用
50 expect.assertions(3);
51 const resultMock = Promise.resolve('test mock');
52
53 // 监听并Mock掉appService.getAllUsers函数的返回结果,当这个函数有依赖第三方的时候可以使用
54 const spyfn = jest.spyOn(appService, 'getAllUsers').mockImplementation(() => resultMock);
55 expect(await appController.getAllUsers(req, res)).toBe('test mock');
56
57 // 用来判断一个函数是否被调用过
58 expect(spyfn).toHaveBeenCalled();
59
60 // 判断函数被调用过几次
61 expect(spyfn).toHaveBeenCalledTimes(2);
62 done();
63 });
64
65 it('promise throws', async (done) => {
66 expect.assertions(1);
67 const message = 'test service error';
68 const result2 = Promise.reject(new Error(message));
69
70 // 劫持getAllUsers函数并返回一个异常给appController
71 jest.spyOn(appService, 'getAllUsers').mockImplementation(() => result2);
72 await expect(appController.getAllUsers(req, res)).rejects.toThrow(message);
73 done();
74 });
75 });
76 });
配置vscode调试
1 {
2 // 使用 IntelliSense 了解相关属性。
3 // 悬停以查看现有属性的描述。
4 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
5 "version": "0.2.0",
6 "configurations": [
7 {
8 "name": "Debug TypeScript",
9 "type": "node",
10 "request": "launch",
11 "env": {
12 "NODE_ENV": "development"
13 },
14 "runtimeExecutable": "nodemon",
15 "restart": true,
16 "args": [
17 "${workspaceRoot}/src/main.ts"
18 ],
19 "runtimeArgs": [
20 "--config",
21 " nodemon-debug.json",
22 "--nolazy",
23 "-r",
24 "ts-node/register"
25 ],
26 "sourceMaps": true,
27 "disableOptimisticBPs": true,
28 "cwd": "${workspaceRoot}",
29 "protocol": "inspector",
30 "console": "integratedTerminal",
31 "internalConsoleOptions": "neverOpen"
32 },
33 {
34 "type": "node",
35 "request": "launch",
36 "name": "Debug Jest Tests",
37 "program": "${workspaceFolder}/node_modules/.bin/jest",
38 "args": [
39 "-r tsconfig-paths/register",
40 "-r ts-node/register",
41 "--runInBand"
42 ],
43 "console": "integratedTerminal",
44 "internalConsoleOptions": "neverOpen",
45 "disableOptimisticBPs": true,
46 "skipFiles": [
47 "<node_internals>/**"
48 ],
49 },
50 {
51 "type": "node",
52 "request": "launch",
53 "name": "Debug Jest File",
54 "program": "${workspaceFolder}/node_modules/.bin/jest",
55 "args": [
56 "${fileBasenameNoExtension}",
57 "-r tsconfig-paths/register",
58 "-r ts-node/register",
59 "--runInBand"
60 ],
61 "console": "integratedTerminal",
62 "internalConsoleOptions": "neverOpen",
63 "disableOptimisticBPs": true,
64 },
65 ]
66 }
来源:oschina
链接:https://my.oschina.net/u/4417917/blog/4261974