如何对NgRx Effect进行大理石测试?附代码示例
如何用大理石测试为NgRx Effect编写单元测试?
首先先回顾下你写的StoreEffects代码:
@Injectable() export class StoreEffects { constructor( private store: Store<State>, private actions$: Actions, ) { } @Effect() userProfile$ = this.actions$ .ofType('Load') .switchMap(action => { const payLoad = action['payload']; //此处执行加载逻辑 return Observable.of({}); //为简洁起见做了简化 }); }
接下来我会带你一步步实现对应的大理石测试,这种测试方式能非常直观地模拟异步流的时间线,很适合测试NgRx Effect:
第一步:配置测试环境
首先要在测试文件里准备好必要的依赖,用TestBed来配置测试模块,我们需要:
- 导入
EffectsModule来处理Effect的注入 - 使用
provideMockActions来模拟动作流 - 用
provideMockStore来mock Store(因为你的Effect注入了Store)
import { TestBed } from '@angular/core/testing'; import { provideMockActions } from '@ngrx/effects/testing'; import { Observable } from 'rxjs'; import { StoreEffects } from './store.effects'; import { provideMockStore } from '@ngrx/store/testing'; import { cold, hot } from 'jasmine-marbles';
然后在beforeEach里完成配置:
describe('StoreEffects', () => { let effects: StoreEffects; let actions$: Observable<any>; beforeEach(() => { TestBed.configureTestingModule({ imports: [], providers: [ StoreEffects, provideMockActions(() => actions$), provideMockStore({ initialState: {} }) // 这里可以传入你的初始State ] }); effects = TestBed.inject(StoreEffects); });
第二步:编写大理石测试用例
大理石测试的核心是用字符串来表示时间线:
-代表一个时间帧(默认是10ms)a、b等字母代表一个动作的触发^代表订阅开始的时间点|代表流完成#代表流抛出错误
针对你的userProfile$ Effect,我们可以测试:当触发一个带有payload的'Load'动作时,Effect会返回对应的输出(这里你的示例返回空对象,你可以根据实际逻辑调整预期输出)。
完整的测试用例如下:
it('should return an empty object when Load action is dispatched', () => { // 模拟要触发的Load动作,带payload const loadAction = { type: 'Load', payload: { userId: 123 } }; // 模拟Effect的输出结果 const expectedOutput = {}; // 用hot创建一个热Observable,表示动作流:在时间点0触发loadAction actions$ = hot('-a', { a: loadAction }); // 用cold创建预期的输出流:在一个时间帧后返回expectedOutput const expected = cold('-b', { b: expectedOutput }); // 断言Effect的输出是否符合预期 expectObservable(effects.userProfile$).toBe(expected); }); });
关键部分解释
hot()vscold():hot()用来模拟已经存在的流(比如用户触发的动作,是热的,订阅前可能已经有动作发出)cold()用来模拟需要订阅才会发出值的流(比如Effect的输出)
- 大理石字符串和值映射:
'-a'里的a对应后面对象里的loadAction,'-b'里的b对应expectedOutput,这样就能把时间线和具体动作关联起来。 expectObservable:这是jasmine-marbles提供的断言方法,用来验证Observable的输出是否和预期的大理石流一致。
如果后续你把加载逻辑改成真实的HTTP请求,只需要把return Observable.of({})换成HTTP请求,然后在测试里mock HTTP客户端,大理石测试的核心逻辑还是一样的,只需要调整预期的输出即可。
内容的提问来源于stack exchange,提问作者tmp dev
相关产品推荐
相关产品推荐

