我对使用服务作为依赖项对组件进行单元测试存在疑问,此服务器依赖于Http
。
我正在阅读此文档:Test a component with an async service
我的代码与此示例完全相同:
ngOnInit(): void {
this.twainService.getQuote().then(quote => this.quote = quote);
}
顺便说一下,这是我的代码:code
文档说当我测试依赖于其他服务的组件时,我必须:
将服务注入组件:twainService = fixture.debugElement.injector.get(TwainService);
设置间谍:spy = spyOn(twainService, 'getQuote').and.returnValue(Promise.resolve(testQuote));
我这样做: 这是我的spec文件:spec file。 我在第21行提供服务,我在29中注入服务,然后在32中设置间谍。
所以问题是:如果我像文档那样做所有事情我都会收到错误:Error: No provider for Http!
。显然会出现此错误,因为我的GoodsDataService
取决于Http
服务。我应该怎么处理?我这样做了:我创建了简单的javascript对象,并用它嘲笑了我的真实GoodsDataService
。我还在此对象中添加了getGoods
方法存根。所有这些都允许我在不注入真实GoodsDataService
的情况下测试主要组件。但我完全不确定这个解决方案。我认为它很脏而且不正确。什么是单元测试组件/服务的正确方法,这取决于另一个服务,而这又取决于Http
服务?有什么想法吗?
答案 0 :(得分:1)
只需在测试模块的导入中添加HttpModule
即可。
它需要存在才能将Http注入你的服务器中,但是因为你监视你的服务方法,所以你的测试中不会使用Http。
答案 1 :(得分:0)
摘要:是的,使用依赖项存根和异步服务Angular doc示例的组合。
事实证明TwainService
实际上并没有使用Http
或其他依赖项,它只返回一个Promise:
getQuote(): Promise<string> {
return new Promise(resolve => {
setTimeout( () => resolve(this.nextQuote()), 500 );
});
}
因此,在我们的情况下,被测组件依赖于可能具有多种自身依赖关系的服务,最好通过WelcomeComponent
/ userServiceStub
示例来模拟该服务。 Angular文档(继续阅读警告)。存根对象将具有实际方法名称的属性,其值是带有语句的未命名函数。
现在,即使real方法异步返回,也很容易错误地在同步返回的存根中实现一个方法。您不希望这样做,因为被测组件可能包含.then()
块来处理真正的异步方法的响应。因此,请确保您的存根方法返回包含在promise中的testing-return-value:return Promise.resolve(mySwappableTestingReturnValue)
。
最后,因为我们确实正在测试异步方法(警告),it
块也应该使用TwainService
示例中的三个选项之一:angular's async()
/ { {1}},有角度的whenStable.then()
/ fakeAsync()
或茉莉花tick()
。我还发现,承诺done
附加到.then()
的常规fixture.componentInstance.myAsyncMethod()
块同样有效(也可能是js async
/ await
。)
~~~
作为一名间谍新手,我还犯了另一个错误,.and.callThrough()
可以帮助你。
例如(幽默,它简短而且常见):LoginComponent有一个submit-btn,其onclick由调用this.authService.askAuthServer的logMeIn方法处理。 askAuthServer使用Http。
测试按钮单击是否正确调用logMeIn的规范是同步的,我们不关心logMeIn的返回值,我们只关心它被调用(并且UI事件在主线程上同步处理,如果这有助于你)。在logMeIn DOES中测试决策逻辑的规范需要返回值,因此需要异步测试,所以我们使用whenStable().then()
。
因此,您很高兴在beforeEach
中创建了一个spyOn logMeIn,但是单击规范成功并且异步逻辑规范失败。在点击规范中,你会注意到askAuthServer没有执行,尽管我们的间谍成功.toHaveBeenCalled()
。到底是怎么回事?这是因为间谍阻止了logMeIn的执行,甚至在我们选择不等待logMeIn的返回之前。所以在逻辑规范中,尽管它可能没有使用logMeInSpy,但即使我们正确设置了异步部分,间谍仍然会阻止执行logMeIn(以及askAuthServer)。
了解这一点,在.and.callThrough()
中创建间谍时使用beforeEach
,在两个规范中使用允许执行 logMeIn,或者将间谍移动到点击规范中它不会影响逻辑规范。