如何测试NgRx Router Store选择器?组合选择器测试配置
我来帮你搞定这个NgRx选择器的测试难题!针对那些依赖RouterState参数的组合选择器,我们可以通过模拟RouterState的状态来搭建独立的测试套件,下面是具体的步骤和示例代码:
1. 准备测试依赖
首先确保你的测试文件中导入了NgRx测试工具、Router相关类型以及你自己定义的reducers和状态:
import { TestBed } from '@angular/core/testing'; import { provideMockStore, MockStore } from '@ngrx/store/testing'; import { RouterReducerState } from '@ngrx/router-store'; import { State, getRouterState, getRouterStateUrl, isSomeIdParamValid } from './reducers'; import { fromAuth, AuthState } from './auth.reducer';
2. 配置测试环境与模拟初始状态
我们使用provideMockStore来创建一个模拟的Store,同时定义好RouterState和AuthState的初始模拟数据——注意RouterState必须符合RouterReducerState的结构(包含state和navigationId两个属性):
describe('NgRx Selectors', () => { let store: MockStore<State>; // 模拟RouterState的初始状态 const mockInitialRouterState: RouterReducerState<{ params: { someId?: string }, url: string, queryParams: {} }> = { state: { url: '/test-path', queryParams: {}, params: {} }, navigationId: 1 // 这个属性是@ngrx/router-store要求必须存在的 }; // 模拟AuthState的初始状态 const mockInitialAuthState: AuthState = { loggedIn: false }; beforeEach(() => { TestBed.configureTestingModule({ providers: [ provideMockStore({ initialState: { router: mockInitialRouterState, auth: mockInitialAuthState } as State }) ] }); store = TestBed.inject(MockStore); });
3. 编写选择器测试用例
接下来就可以针对你的选择器编写测试了,比如先测试isSomeIdParamValid:
describe('isSomeIdParamValid', () => { it('应该在someId参数不存在时返回false', () => { const result = isSomeIdParamValid(store.state); expect(result).toBe(false); }); it('应该在someId参数存在时返回true', () => { // 更新模拟Store中的RouterState,添加someId参数 store.setState({ ...store.state, router: { ...mockInitialRouterState, state: { ...mockInitialRouterState.state, params: { someId: '12345' } } } }); const result = isSomeIdParamValid(store.state); expect(result).toBe(true); }); });
如果有需要组合RouterState和AuthState的选择器(比如判断用户是否有权限访问当前路由),也可以用同样的方式测试:
// 假设你有这样的组合选择器 // export const canAccessTargetRoute = createSelector( // isSomeIdParamValid, // fromAuth.getLoggedIn, // (isValidId, isLoggedIn) => isValidId && isLoggedIn // ); describe('canAccessTargetRoute', () => { it('应该在用户未登录但someId有效时返回false', () => { store.setState({ ...store.state, router: { ...mockInitialRouterState, state: { ...mockInitialRouterState.state, params: { someId: '12345' } } } }); const result = canAccessTargetRoute(store.state); expect(result).toBe(false); }); it('应该在用户已登录且someId有效时返回true', () => { store.setState({ ...store.state, router: { ...mockInitialRouterState, state: { ...mockInitialRouterState.state, params: { someId: '12345' } } }, auth: { ...mockInitialAuthState, loggedIn: true } }); const result = canAccessTargetRoute(store.state); expect(result).toBe(true); }); }); });
几个关键注意点
- 务必保证模拟的RouterState结构完整,
navigationId是@ngrx/router-store要求的必填属性,不能省略。 - 选择器本质是纯函数,测试时直接调用选择器并传入模拟的state即可,不需要dispatch任何动作,这样测试会更高效且独立。
- 如果你的选择器依赖其他子选择器(比如
getRouterState),测试时不需要单独测试子选择器,只需要确保传入的state能被正确解析即可。
内容的提问来源于stack exchange,提问作者BlackHoleGalaxy
相关产品推荐
相关产品推荐

