开发angular项目的时候,并不是只有前端开发人员在编写单元测试。

jest 单元测试 angular

15:01 · 2026年01月07日 · 周三 show: --

前端Angular项目中使用jest编写单元测试技巧

开发angular项目的时候,并不是只有前端开发人员在编写单元测试。

最近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比较了解,那么,写出覆盖率高的单元测试还不是手到擒来吗?

最后一次更新时间: 15:01 · 2026年01月07日 · 周三