最近angular用的很多,一年前我并没有写过单元测试,刚写的时候用AI写,有的时候能过,但是我改了后又得去问ai,它生成的代码又看不大懂,分享下我写单元测试的方法,非常简单还很高效,虽然不是官方推荐的。
为什么能轻松100%覆盖率
首先,核心思想就是单元测试颗粒度最细应该是到一个方法,那么这个方法会用到的其他方法都可以被模拟,一个模块文件中引入的所有其他模块都可以被模拟,不考虑方法依赖问题,只考虑被测试的这个方法的全部分支被运行,所以各项覆盖率可以全100%。
首先,怎么运行单元测试?
// 运行所有单元测试
npm run test
// 运行单个文件
npm test src/app/service/common.util.service.spec.ts使用参数 --verbose 可以在控制台打印jest消息
接下来就是写单元测试了,先看一个源码例子
import { Component, Input, Output, EventEmitter, OnInit, OnChanges } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { deepClone } from '../../../../../app/utils/common.utils';
@Component({
selector: 'test-component',
templateUrl: './component.html',
styleUrls: ['./component.scss'],
standalone: false,
})
export class TestComponent {
form: any = {};
constructor(public translateService: TranslateService) {}
ngOnInit(): void {
this.loadOptions();
}
loadOptions(){}
}单元测试代码,除了第三方的模块,其他的模块全部模拟,方法调用直接prototype访问类的方法,并且模拟this对象。
import { TestComponent } from './component';
jest.mock('../../../../../app/utils/common.utils', () => ({
deepClone(_) {
return { ..._ };
},
}));
describe('TestComponent', () => {
beforeEach(() => {});
it('应当正确调用 constructor', () => {
const component = new TestComponent(null, null);
expect(component['test']).toEqual(undefined);
});
it('应当正确调用 ngOnInit', () => {
const fn = TestComponent.prototype.ngOnInit;
const component = {
loadOptions() {}, // 此处就是模拟的依赖方法了
};
fn.call(component);
expect(component['test']).toEqual(undefined);
});
it('应当正确调用 loadOptions', () => {
const fn = TestComponent.prototype.loadOptions;
const component = {};
fn.call(component);
expect(component['test']).toEqual(undefined);
});
});我使用的方式可能简单暴力,但我觉得此方式很有效,可以将一个方法可以处理的问题全部考虑到,所有分支都能运行到,可操作性很大。当然,你如果想要写出更好的单元测试直接看jest文档即可,我只是提出一种方式。
一些额外技巧
你可以修改模拟的其他模块的方法
test('should unmock specific module', () => {
const service = require('../service/rule.service');
service.TimeService = class {};
// 还原
jest.unmock('../service/rule.service');
});可以在每个测试结束还原spyOn模拟的方法
afterEach(() => {
jest.restoreAllMocks();
});结语
既然所有方法都能模拟了,如果你对js比较了解,那么,写出覆盖率高的单元测试还不是手到擒来吗?
