目标:我想为基本的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请求以测试这种效果。
答案 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);
})
});