【问题标题】:Unit testing NgRx effect (invoking other effect) to ensure service method called twice单元测试 NgRx 效果(调用其他效果)以确保服务方法被调用两次
【发布时间】:2021-02-24 04:57:33
【问题描述】:

我正在使用 ngrx 8.3.0 并想测试我的效果类。其中一部分是这样的:

    @Effect()
    onSubmit$ = this.actions.pipe(
        ofType<RequestSubmission>(SubmissionActionType.REQUEST_SUBMISSION),
        switchMap(request => {
            return this.service
                .submit(request.content.slice((request.iteration - 1) * 2,request.iteration * 2))
                .pipe(map(s => SubmissionAction.submissionAccepted(request.content, s, request.iteration)),
                    catchError(error => of(SubmissionAction.submissionFailed(error.status)))
                );
        })
    );

    @Effect()
    submissionAccepted$ = this.actions.pipe(
        ofType<SubmissionAccepted>(SubmissionActionType.SUBMISSION_ACCEPTED),
        map(request =>
            request.iteration * 2 < request.content.length
                ? SubmissionAction.requestSubmission(request.content, request.iteration + 1)
                : SubmissionAction.submissionCompleted()
        )
    );

如您所见,第二个效果监听在第一个效果中调用的动作。此外(如果满足条件)第二个效果调用第一个效果监听的动作。这样我们循环遍历数组 content 并每次调用服务函数submit 2 个元素,直到数组到达其末尾。

我现在想测试长度为 3 的内容,我的服务的 submit 函数被调用了两次。到目前为止,我有以下内容:

    it('should call submit method twice', async () => {
        const countSpy = spyOn(service, 'submit').and.callThrough();

        actions$ = new ReplaySubject(1);
        const content = ['a80b04a8','155b5a51','a19d0a7a'];
        actions$.next(SubmissionAction.requestSubmission(content, 1));

        await effects.onSubmitReference$.subscribe();
    
        expect(countSpy).toHaveBeenCalledTimes(2);
    
    });

不幸的是,间谍检测到该函数只被调用了一次。

我也考虑过在期望函数被调用两次之前独立订阅第二个效果


actions$.next(SubmissionAction.submissionAccepted(content,{result: []}, 1));
await effects.submissionAccepted$.subscribe();

但我得到了相同的结果。有谁知道在测试中订阅第一个效果是否应该自动调用第二个效果? 提前感谢您的宝贵时间。

【问题讨论】:

  • 看起来第二个效果只是返回动作,但调度任何动作,所以这可能是问题所在。如果它仍然不起作用,创建一个 StackBlitz 演示会很有帮助。 Here's 一个可以开始的样板项目。
  • 非常感谢您的评论。实现工作正常,我已经手动测试过了。我无法通过测试,因为我不确定是否通过调用第一个操作并订阅第一个效果,所有过程(调用的新效果)是否会像现实生活中的代码一样自动完成。
  • 我认为如果不调度测试用例中第二个效果的动作,它将无法工作。
  • 如果我将它们分开发送,这有点超出了测试的全部目的,但再次感谢您的意见
  • 我正在尝试测试现有的实现,显然我可能不得不重构实现本身。

标签: angular unit-testing jestjs ngrx


【解决方案1】:

在同事的帮助下,我终于能够测试代码。在测试中,我不再期望服务函数被调用两次,而是遵循完整的效果流程。

it(`should process effects loop correctly`, (done: DoneCallback) => {
    actions$ = new Subject<SubmissionAction>();
    const content = ['a80b04a8','155b5a51','a19d0a7a'];
    let iteration = 1;
    jest.spyOn(service, 'submitReference').mockImplementation(() => {
        const status = 'SUBMITTED';
        const submissionNumbers = content.slice((iteration - 1) * 2, iteration * 2)
        return of(<Submissions>{ submissionNumbers });
    });
    effects.onSubmit$.subscribe(action => {
        expect(action.type).toEqual(SubmissionActionType.SUBMISSION_ACCEPTED);
        actions$.next(action);          
    });
    effects.submissioneAccepted$.subscribe(action => {
        iteration++;
        if (iteration < 3) {
            expect(action.type).toEqual(SubmissionActionType.REQUEST_SUBMISSION);
            expect((action as RequestSubmission).iteration).toEqual(2);
            actions$.next(action);  
        } else {
            expect(action.type).toEqual(SubmissionActionType.SUBMISSION_COMPLETED);
            actions$.complete();            
            done();
        }
    });
    actions$.next(SubmissionAction.requestSubmission(content, iteration));
});

更清楚地说,我们订阅了这两种效果(onSubmit 和 submiteAccepted),并期望根据循环的迭代调用适当的操作。循环完成后,订阅和测试也完成。最后我们dispatch第一个action来触发整个流程

【讨论】:

    猜你喜欢
    • 2019-06-15
    • 2020-01-20
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    • 2020-11-06
    • 1970-01-01
    • 2019-02-12
    相关资源
    最近更新 更多