You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:00:10