使用Jasmine Marbles测试时NGRX Effect未执行的排查求助
问题排查与修复方案
我来帮你梳理下导致Effect未运行、测试断言失败的几个关键问题:
1. 依赖注入拼写错误
这是最核心的问题:你在TestBed配置里把useValue写成了小写的usevalue,导致AuthService的Spy没有被正确注入到Effect中。Effect实际调用的不是你模拟的Spy,自然不会触发后续的动作流。
错误代码:
{ provide: AuthService, usevalue: { completeAuthentication: completeAuthSpy } }
修正后:
{ provide: AuthService, useValue: { completeAuthentication: completeAuthSpy } }
2. 测试变量初始化污染风险
你把actions$定义在了beforeEach外部,这会导致不同测试用例之间的状态污染。建议在每次测试前重新初始化actions$:
let actions$: Observable<Action>; // 仅声明类型 let completeAuthSpy: jasmine.Spy; let userEffects: UserEffects; beforeEach(() => { actions$ = new Observable<Action>(); // 每次测试重新初始化 completeAuthSpy = jasmine.createSpy(); // ... 其他TestBed配置 });
3. 时间线与Marble语法细节
你的Marble时间线逻辑是对的,但可以调整得更严谨:确保response的完成信号和expected的时间线完全匹配。另外,注意你创建的User对象中state设为了undefined,虽然不影响测试运行,但如果业务逻辑期望state有值,后续可能需要调整。
修正后的完整测试代码
import { UserEffects } from './user.effects'; import { AuthService } from './../../core/services/auth.service'; import { ApiServiceMock, ApplicationInsightServiceMock, AppSettingsServiceMock, AuthServiceMock, RouterMock, UserServiceMock } from './../../../testing-utils/mocks/service-mocks'; import { TestBed } from '@angular/core/testing'; import { Action } from '@ngrx/store'; import { provideMockActions } from '@ngrx/effects/testing'; import { Observable } from 'rxjs'; import * as userActions from '../actions/user.actions'; import { cold, hot } from 'jasmine-marbles'; import { User } from 'oidc-client'; let actions$: Observable<Action>; let completeAuthSpy: jasmine.Spy; let userEffects: UserEffects; beforeEach(() => { actions$ = new Observable<Action>(); completeAuthSpy = jasmine.createSpy(); TestBed.configureTestingModule({ providers: [ provideMockActions(() => actions$), UserEffects, AppSettingsServiceMock, ApiServiceMock, UserServiceMock, RouterMock, ApplicationInsightServiceMock, { provide: AuthService, useValue: { completeAuthentication: completeAuthSpy } } ], }); userEffects = TestBed.inject(UserEffects); }); describe('UserEffects', () => { describe('CompleteAuthentication', () => { it('Should dispatch authenticationSuccess action on success', () => { const userState = new User({ id_token: 'TestID', session_state: 'TestState', access_token: 'TestToken', refresh_token: 'TestRefreshToken', token_type: 'TestTokenType', scope: 'TestScope', profile: {} as any, expires_at: 6, state: 'test-user-state', // 可以设置一个具体值便于验证 }); const outcome = userActions.authenticationSuccess({ value: userState.state }); const response = cold('-a|', { a: userState }); const expected = cold('--b', { b: outcome }); completeAuthSpy.and.returnValue(response.toPromise()); actions$ = hot('-c', { c: userActions.completeAuthentication }); expect(userEffects.compelteAuthentication$).toBeObservable(expected); expect(completeAuthSpy).toHaveBeenCalled(); }); }); });
额外提示
注意你的Effect属性名compelteAuthentication$存在拼写错误(少了一个字母l,正确应为completeAuthentication$),虽然当前测试能匹配,但建议统一修正,避免后续维护混淆。
内容的提问来源于stack exchange,提问作者Chirag Patel
相关产品推荐
相关产品推荐

