用vscode进行jest单元测试并调试代码
首先需要安装相应的包: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 }