如何为含if else的MatSelectChange方法编写单元测试实现100%覆盖率
selectionChanged方法100%覆盖率测试方案
要拿到100%代码覆盖率,核心是把方法里所有语句、所有分支路径全跑到,这个方法一共3条可执行路径,把依赖的service做个mock,写3个用例就能全覆盖,具体如下:
测试前准备
先把方法里依赖的service做mock,给doSomething、doSomethingElse两个方法插桩打spy,一来不用真的跑service里的业务逻辑,二来能方便判断方法到底有没有被调用。不用费劲构造真实的MatSelectChange实例,直接写个带value属性的普通对象,强转成MatSelectChange类型当入参就行,完全符合TS类型要求,测试跑起来也更快。
具体测试用例
三个用例对应三条执行路径,缺一个都拿不到100%覆盖率:
- 入参value等于'1'的场景
造个value为'1'的mock入参,调用selectionChanged之后,检查service.doSomething是不是刚好被调用了1次,同时service.doSomethingElse完全没被调用。 - 入参value等于'2'的场景
造个value为'2'的mock入参,调用方法之后,检查service.doSomethingElse刚好被调用1次,service.doSomething完全没被调用。 - 入参value既不是'1'也不是'2'的场景
这是大部分人会漏的隐式分支——两个if判断都不命中的情况,随便选个非'1'/'2'的值当入参就行,比如'3'、null、undefined、空字符串都可以,调用方法之后检查两个service方法都没被调用。
参考测试代码(Angular + Jasmine环境)
// 先mock依赖的service const mockService = jasmine.createSpyObj('TargetService', ['doSomething', 'doSomethingElse']); let component: TestComponent; beforeEach(() => { TestBed.configureTestingModule({ providers: [ TestComponent, { provide: TargetService, useValue: mockService } ] }); component = TestBed.inject(TestComponent); }); it('入参value为1时,调用service.doSomething', () => { // 重置spy调用记录,避免其他用例的调用结果干扰当前断言 mockService.doSomething.calls.reset(); mockService.doSomethingElse.calls.reset(); const mockSelectEvent = { value: '1' } as MatSelectChange; component.selectionChanged(mockSelectEvent); expect(mockService.doSomething).toHaveBeenCalledTimes(1); expect(mockService.doSomethingElse).not.toHaveBeenCalled(); }); it('入参value为2时,调用service.doSomethingElse', () => { mockService.doSomething.calls.reset(); mockService.doSomethingElse.calls.reset(); const mockSelectEvent = { value: '2' } as MatSelectChange; component.selectionChanged(mockSelectEvent); expect(mockService.doSomethingElse).toHaveBeenCalledTimes(1); expect(mockService.doSomething).not.toHaveBeenCalled(); }); it('入参value为其他值时,不调用任何service方法', () => { mockService.doSomething.calls.reset(); mockService.doSomethingElse.calls.reset(); // 这里选'3'当测试值,换成null/undefined等边界值也可以 const mockSelectEvent = { value: '3' } as MatSelectChange; component.selectionChanged(mockSelectEvent); expect(mockService.doSomething).not.toHaveBeenCalled(); expect(mockService.doSomethingElse).not.toHaveBeenCalled(); });
补个提醒:哪怕你业务上能100%保证下拉选项只会传'1'和'2',第三个用例也得写。覆盖率统计是按代码实际的分支节点算的,和你业务上的入参约束没关系,只有跑到两个if都不命中的路径,分支覆盖率才能到100%。
内容的提问来源于stack exchange,提问作者user16814898
相关产品推荐
相关产品推荐

