如何通过模拟Http响应来测试NgRx效果

时间:2020-09-11 17:21:05

标签: angular unit-testing rxjs jasmine ngrx

目标:我想为基本的NgRx效果编写适当的单元测试。到目前为止,使用茉莉花大理石时我的尝试都没有成功。

这是我要测试的效果:

markMovieAsFinished$ = createEffect(() =>
  this.actions$.pipe(
    ofType(MovieActions.markMovieAsFinished),
    switchMap((action: Action) => {
      return this.http.put(`/api/reading-list/${action.item.movieId}/finished`, { finishedDate: action.item.finishedDate })
      .pipe(
          switchMap(() => EMPTY) // With an optimistic update, we initially handle the 'markMovieAsFinished' action directly in the reducer, hence, no need to dispatch another action on a successful PUT request!
      );
    })
  )
);

这是我最近一次使用大理石测试的尝试。 (我在实施大理石测试方面非常陌生!):

describe('MovieEffects', () => {
  let actions$: Actions;
  let effects: MovieEffects;
  let httpMock: HttpTestingController;


  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ NxModule.forRoot(), SharedTestingModule ],
      providers: [
        MovieEffects,
        DataPersistence,
        provideMockActions(() => actions$)
      ]
    });

    actions$ = TestBed.inject(Actions);
    effects = TestBed.inject(MovieEffects);
    httpMock = TestBed.inject(HttpTestingController);
  });


  describe('markMovieAsFinished$', () => {
    it('should return an EMPTY observable with the outcome, on success', () => {
    const action: Action = MovieActions.markMovieAsFinished({ finishedDate: '1/1/20'});
    const completion = EMPTY;

    // setup the Effect
    actions$ = hot('-a', { a: action });
    const response = cold('-b|', { b: {} }); // payload from successful response can just be an empty object
    const expected = cold('--c', { c: completion });

    expect(effects.markMovieAsFinished$).to.be.eql(expected);
    
    })
  });

当我尝试上述尝试时,markMovieAsFinished $值返回一个空数组。在上面的代码中,我已经设置了单元测试的安排和声明部分。我不了解的部分是如何模拟成功的PUT请求以测试这种效果。

3 个答案:

答案 0 :(得分:1)

我不知道什么是大理石测试,但是我确实知道我正在以不同的方式构建效果。

markMovieAsFinished$ = this.actions$.pipe(
    ofType(MovieActions.markMovieAsFinished),
    mergeMap((action) => {
        return this.http.put(`/api/reading-list/${action.item.movieId}/finished`, { finishedDate: action.item.finishedDate }).pipe(
        map((resp) => Success,
        catchError(() => Failure)
        );
    })
    );

希望它可以提供帮助

答案 1 :(得分:1)

要测试效果的put部分,您只需测试调用了正确的参数

spyOnProperty(action,'item').and.returnValue({movieId : 1});

spyOn(effects.http, 'put').and.callFake((url: string, data: any) => {
  expect(url).toEqual('/api/reading-list/1/finished');
  expect(data).toEqual({ finishedDate: '1/1/20' });
})

答案 2 :(得分:0)

我会将HTTP调用移至服务,然后将该服务注入效果。这将使测试服务和效果更加容易,并且可以更好地分离关注点。测试效果时,您将模拟此服务。

尽管如此,我们将根据您的要求创建一个伪造的HTTP:

1。)摆脱HttpTestingController(在这种情况下您不需要它)

2。)使用put方法创建一个伪造的HTTP。

3。)返回伪造的HTTP的模拟值,然后进行断言

describe('MovieEffects', () => {
  let actions$: Actions;
  let effects: MovieEffects;
  let mockHttpClient = any;

  beforeEach(() => {
    TestBed.configureTestingModule({
      // the name ('http') goes as the first argument and an array of public methods you want to spyOn
      mockHttpClient = jasmine.createSpyObj('http', ['put']);
      imports: [ NxModule.forRoot(), SharedTestingModule ],
      providers: [
        MovieEffects,
        DataPersistence,
        provideMockActions(() => actions$),
        { provide: HttpClient, useValue: mockHttpClient }
      ]
    });

    actions$ = TestBed.inject(Actions);
    effects = TestBed.inject(MovieEffects);
  });


  describe('markMovieAsFinished$', () => {
    it('should return an EMPTY observable with the outcome, on success', () => {
    const action: Action = MovieActions.markMovieAsFinished({ finishedDate: '1/1/20'});
    const completion = EMPTY;

    // setup the Effect
    actions$ = hot('-a', { a: action });
    const response = cold('-b|', { b: {} }); // payload from successful response can just be an empty object
    const expected = cold('--c', { c: completion });
    mockHttpClient.put.and.returnValue(response); // make the mockHttpClient return fake response
    // do your assertion
    expect(effects.markMovieAsFinished$).to.be.eql(expected);
    
    })
  });