如何在测试服务的测试套件中途为该服务注入其他依赖项模拟?

时间:2020-10-27 20:09:58

标签: angular unit-testing jestjs

在测试Angular服务(具有其自己的依赖项)时,我经常发现自己一直在测试测试套件中的快乐路径和悲伤路径。

我的意思是我有这项服务:

export class MyService {
  constructor(private MyClient) {}

  public doIt() {
    return this.myClient.doTheThing().pipe(
      catchError(error => {
        // error handling logic
      }),
      // process the response
    )
  }
}

现在,我想测试MyService#doIt成功运行并返回该请求的响应/结果的可观察值,以及MyClient#doTheThing失败和错误时的测试结果(自从我MyClient#doTheThing中有一些逻辑要测试)。

测试幸福的道路很容易:

catchError

但是,当// MyClientMock is a mock implementation of MyClient that returns a canned result // for instance so that I can test against these values when running the tests. describe(MyService, () => { let service: MyService beforeEach(() => { TestBed.configureTestingModule({ providers: [ MyService, { provide: MyClient, useClass: MyClientMock } ], }) service = TestBed.inject(MyService) }) it('does the thing', (done) => { service.doIt().subscribe(result => { expect(result).toEqual('something') done() }) }) }) 抛出错误时,如何测试悲伤的路径,并确保MyClient中的逻辑符合我的预期?

我考虑过创建另一个catchError并将其命名为MyClientMock并将其抛出。但是我不能注入它,因为它已经在测试开始时就已经设置好了,并且会干扰其他测试用例。

在这种情况下,有什么好的模式可以用来测试依赖项错误或成功后会发生什么?

1 个答案:

答案 0 :(得分:0)

我强烈推荐Jest,胜过业力。

当您需要重新创建模拟函数的复杂行为以使多个函数调用产生不同的结果时,请使用mockImplementationOnce方法:

const myMockFn = jest
  .fn()
  .mockImplementationOnce(cb => cb(null, true))
  .mockImplementationOnce(cb => cb(null, false));

myMockFn((err, val) => console.log(val));
// > true

myMockFn((err, val) => console.log(val));
// > false

这里是模拟的另一个示例,该模拟根据条件参数生成结果:

import { when } from 'jest-when';

const fn = jest.fn();
when(fn).calledWith(1).mockReturnValue('hello world!');

const result = fn(1);
expect(result).toEqual('hello world!');

我想说Jest优于Karma的最大优点是它的非加密,直接的错误消息,使您可以一目了然地确定测试失败的根本原因。