如何测试依赖于另一项服务的服务/组件,而这又取决于Http服务?

时间:2017-05-30 22:05:39

标签: angular unit-testing http

我对使用服务作为依赖项对组件进行单元测试存在疑问,此服务器依赖于Http。 我正在阅读此文档:Test a component with an async service

我的代码与此示例完全相同:

  ngOnInit(): void {
    this.twainService.getQuote().then(quote => this.quote = quote);
  }

顺便说一下,这是我的代码:code

文档说当我测试依赖于其他服务的组件时,我必须:

  1. 将此服务设置为模块提供程序
  2. 将服务注入组件:twainService = fixture.debugElement.injector.get(TwainService);

  3. 设置间谍:spy = spyOn(twainService, 'getQuote').and.returnValue(Promise.resolve(testQuote));

  4. 我这样做: 这是我的spec文件:spec file。 我在第21行提供服务,我在29中注入服务,然后在32中设置间谍。

    所以问题是:如果我像文档那样做所有事情我都会收到错误:Error: No provider for Http!。显然会出现此错误,因为我的GoodsDataService取决于Http服务。我应该怎么处理?我这样做了:我创建了简单的javascript对象,并用它嘲笑了我的真实GoodsDataService。我还在此对象中添加了getGoods方法存根。所有这些都允许我在不注入真实GoodsDataService的情况下测试主要组件。但我完全不确定这个解决方案。我认为它很脏而且不正确。什么是单元测试组件/服务的正确方法,这取决于另一个服务,而这又取决于Http服务?有什么想法吗?

2 个答案:

答案 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,或者将间谍移动到点击规范中它不会影响逻辑规范。