Angular测试问题:createSpyObj创建的服务模拟方法未被调用
解决Angular组件测试中服务方法调用断言失败的问题
你的测试断言失败的核心原因是你给组件的edit方法创建了spy,但默认情况下这个spy会替换掉原方法的逻辑,并不会真正执行edit里的代码。所以当你调用component.edit()时,只是触发了spy的调用计数,而实际的this.testService.getCase()根本没被执行,自然会断言失败。
两种可行的解决方案
方案一:让spy执行原方法逻辑
如果你确实需要验证edit方法被调用的次数,同时还要确保原方法执行,可以给spy加上.and.callThrough(),这样spy会在记录调用的同时,执行原方法的代码:
it('expect service has been called', () => { // 添加.and.callThrough()让spy执行原方法 spyOn(component, 'edit').and.callThrough(); component.edit(); expect(component.edit).toHaveBeenCalledTimes(1); // 现在服务的getCase方法会被执行,断言就能通过了 expect(testServiceMock.getCase).toHaveBeenCalledWith('id'); // 更精确的断言,验证参数是否正确 });
方案二:去掉组件edit方法的spy(更直接)
其实你的测试核心是验证edit方法是否正确调用了服务的getCase,如果不需要验证edit方法本身的调用次数,完全可以去掉spyOn(component, 'edit'),直接调用原方法:
it('expect service has been called', () => { component.edit(); // 验证服务方法被调用,并且传入了正确的参数'id' expect(testServiceMock.getCase).toHaveBeenCalledWith('id'); });
额外优化建议
- 最好给
testServiceMock.getCase返回一个可观察对象,避免组件里的subscribe报错(虽然当前测试没测订阅后的逻辑,但这是个好习惯):
在beforeEach里添加:import { of } from 'rxjs'; // 需要导入rxjs的of操作符 // ... 其他代码 beforeEach(() => { fixture = TestBed.createComponent(TestComponent); component = fixture.componentInstance; // 让mock的getCase返回一个空的可观察对象 testServiceMock.getCase.and.returnValue(of({})); fixture.detectChanges(); }); - 用
toHaveBeenCalledWith替代toHaveBeenCalled,可以更精确地验证服务方法是否传入了正确的参数,让测试更健壮。
内容的提问来源于stack exchange,提问作者BergkampHUN
相关产品推荐
相关产品推荐

