在 React 中测试 Actions、Reducers 和 Contexts

Posted

技术标签:

【中文标题】在 React 中测试 Actions、Reducers 和 Contexts【英文标题】:Testing Actions, Reducers, & Contexts in React 【发布时间】:2020-03-21 02:51:45 【问题描述】:

我已经使用 Hooks 和 Context 构建了多个 React 功能组件。一切正常。现在我需要为所有内容编写测试。我对如何与其中一些人一起前进感到困惑,因此想与社区联系。

操作 以下是我的一个 Actions 文件的示例:

export const ADD_VEHICLE: 'ADD_VEHICLE' = 'ADD_VEHICLE';
export const UPDATE_VEHICLE: 'UPDATE_VEHICLE' = 'UPDATE_VEHICLE';

type AddVehicleAction = type: typeof ADD_VEHICLE, isDirty: boolean;
type UpdateVehicleAction = type: typeof UPDATE_VEHICLE, id: number, propName: string, payload: string | number;

export type VehiclesActions = 
     | AddVehicleAction
     | UpdateVehicleAction;

我应该如何测试这个 Actions 文件?我的意思不是与其他任何东西结合,我的意思是它,而且只有它? 从 cmets 看来,我同意此文件中没有可直接测试的内容。

减速器 我的每个 Reducers 文件都直接连接到并支持特定的 Context。这是我的一个 Reducers 文件的示例:

import type  VehiclesState  from '../VehiclesContext';
import type  VehiclesActions  from '../actions/Vehicles';
import type  Vehicle  from '../SharedTypes';

import  ADD_VEHICLE,
         UPDATE_VEHICLE
        from '../actions/Vehicles';

export const vehiclesReducer = (state: VehiclesState, action: VehiclesActions) => 
  switch (action.type) 

  case ADD_VEHICLE: 
    const length = state.vehicles.length;
    const newId = (length === 0) ? 0 : state.vehicles[length - 1].id + 1;
    const newVehicle = 
      id: newId,
      vin: '',
      license: ''
    ;

    return 
      ...state,
      vehicles: [...state.vehicles, newVehicle],
      isDirty: action.isDirty
    ;
  

  case UPDATE_VEHICLE: 
    return 
      ...state,
      vehicles: state.vehicles.map((vehicle: Vehicle) => 
        if (vehicle.id === action.id) 
          return 
            ...vehicle,
            [action.propName]: action.payload
          ;
         else 
          return vehicle;
        
      ),
      isDirty: true
    ;
  

如果您想为这个 Reducers 文件构建测试,您会使用什么方法?我的想法是像这样渲染 DOM:

function CustomComponent() 
  const vehiclesState = useVehiclesState();
  const  isDirty,
          companyId,
          vehicles 
         = vehiclesState;  
  const dispatch = useVehiclesDispatch();

  return null;


function renderDom() 
  return 
    ...render(
      <VehiclesProvider>
        <CustomComponent />
      </VehiclesProvider>
    )  
  ;

虽然上面的代码确实运行了,但我现在遇到的问题是 vehiclesStatedispatch 在我的测试代码中都无法访问,所以我试图弄清楚如何在每个 describe / it 中“显示”它们构造。任何建议将不胜感激。

上下文 我的上下文遵循 Kent C. Dodds 概述的相同模式:https://kentcdodds.com/blog/how-to-use-react-context-effectively - StateContext 和 DispatchContext 是分开的,并且有一个默认状态。鉴于此 Code Pattern,并且我已经为 Context 的 Reducers 准备了一个单独的测试文件,那么具体可以针对 Context 测试什么?

【问题讨论】:

感觉太宽泛了!此外,这取决于您要测试的内容,然后实施主要基于意见。 真的不清楚你在问什么。您在上面发布的代码只是类型声明,没有什么要测试的。您可能想用更明确的问题更新您的帖子 @EmileBergeron 你能详细说明一下吗? @ChristopherFrancisco 我已根据您的反馈更新了问题。对于初学者,我相信我已经同意测试 Actions 文件是不可能/不必要的。您将如何测试一个 Reducers 文件,例如我所概述的文件。并且测试 Context(使用类似于 Kent C. Dodds 的代码)是否是不必要的,因为在测试 Reducer 时会执行所有基本操作? 你读过关于编写测试的 redux 文档吗? redux.js.org/recipes/writing-tests这对你来说可能是一个好的开始 【参考方案1】:

和我的评论一样,我真的认为你应该阅读redux docs for writing tests,以便大致了解该怎么做。

但是既然你已经有一个 reducer,你想编写你的测试用例来遵循这个模式

    每个操作至少要进行 1 次测试 每个测试都有一个“先前状态”,该状态将被更改 你将调用你的 reducer,传递动作和之前的状态 您将断言您的新状态与预期相同

这是一个代码示例:

it('adds a new car when there are no cars yet', () => 
  // you want to put here values that WILL change, so that you don't risk
  // a false positive in your unit test
  const previousState = 
    vehicles: [],
    isDirty: false,
  ;

  const state = reducer(previousState,  type: ADD_VEHICLE );

  expect(state).toEqual(
    vehicles: [
      id: 1,
      vin: '',
      license: '',
    ],
    isDirty: true,
  );
);

it('adds a new car when there are existing cars already, () => 
  // ...
);

我还建议使用动作创建者而不是直接创建动作对象,因为它更具可读性:

// actions.js
export const addVehicle = () => (
  type: ADD_VEHICLE
)

// reducer.test.js
it('adds a new car when there are no cars yet', () => 
  //...
  const state = reducer(previousState, actions.addVehicle());

【讨论】:

非常感谢!我会立即阅读您推荐给我的文件。

以上是关于在 React 中测试 Actions、Reducers 和 Contexts的主要内容,如果未能解决你的问题,请参考以下文章

webpack项目篇(六十六):react 全家桶 和 webpack 开发 h5 商城项目的整体思路

如何在“react-native-router-flux”中绑定到 onPress 事件的函数中调用 Actions.xxx

测试异步嵌套组件

React Redux - this.props.actions.fetchPosts 不是函数

React createRef 不可分配给 React Native Actions Sheet ref prop 中的 MutableRefObject 类型

typescript React-Redux与Typescript:actions.ts