【问题标题】:dispatch(action) doesn't immediately update redux state in unit testsdispatch(action) 不会立即更新单元测试中的 redux 状态
【发布时间】:2016-01-01 12:27:53
【问题描述】:

我正在为我的基于 react 和 redux 的应用程序编写测试用例。

container = TestUtils.renderIntoDocument(
  <Provider store={createStore({"key": "old_val"})}>
    {() => <Component />}
  </Provider>
);

在使用initialState 渲染后,我调度一个动作并查看状态是否改变。

Component.store.dispatch({ type: 'SET_VAL', value: 'some_val' });

然后我打印状态

console.log(store.getState());

我希望状态为{"key": "some_val"}。但是,它仍然显示{"key": "old_val"}

应用程序工作正常,只是没有测试,所以我的action-creatorsreducers 不会有任何问题。

我在这里做错了吗?顺便说一句,我正在使用 thunk 中间件进行异步操作分派。这会干扰这里吗?如果是,我如何等到异步操作完成?

更新:

redux 测试 shown here 非常简单,但它们似乎工作正常。

store.dispatch(addTodo('Hello'));
expect(store.getState()).toEqual([{
  id: 1,
  text: 'Hello'
}]);

【问题讨论】:

  • 你是否考虑过在不设置 React 的情况下测试你的 action creators 和 reducers? action creators 和 reducers 都只是纯函数,因此很容易自己调用它们并验证输出。如果你愿意,我可以写一个答案来演示。
  • 哦,是的,我意识到我在 Q 中错过了这一点,所以添加了。虽然我还没有为动作创建者和减速器添加测试,但它们工作正常并且我已经验证了。
  • 我想我不明白为什么您需要验证react-redux 的管道在您的应用程序测试中是否正常工作。将react-redux 作为一个单独的库的目的之一是您可以单独测试您的减速器和动作创建器。你能详细说明一下吗?
  • 我正在根据状态在我的组件中呈现一些信息。所以只需要编写测试来验证当我改变状态时渲染的文本是否改变。但你说得有道理,如果我测试单个单元,整体功能应该可以正常工作。
  • 由于状态作为props 传递给您的connected 组件,因此reactreact-redux 负责确保将更新传播到您的组件。如果您需要根据状态更改来测试组件输出,您实际上可以将测试状态作为props 传递,并且也可以单独使用组件。组件是状态的纯(-ish)函数,与 reducer 和 action creators 类似,因此适用相同的想法。

标签: reactjs jasmine redux


【解决方案1】:

redux 的一大好处是它允许您使用纯函数和纯组件来实现几乎所有的应用程序。 Redux 和 react-redux 抽象了订阅 UI 到状态更改的实现细节,这允许您单独测试所有应用程序的代码。这样一来,您就不需要在每次想要测试代码时都渲染出带有商店的提供程序,这大大降低了复杂性。

假设您的状态中有一个key 属性和一个KeyDisplay 组件。您可以使用以下 reducer 文件来实现状态:

reducers.js

import { combineReducers } from 'redux';

export function key(state, { type, value }) {
  switch(type) {
    case 'SET_VAL': return value;
    default: return state;
  }
}

export default combineReducers({ key });

您可以为我们的组件设置一个文件:

KeyDisplay.js

import React from 'react';
import { connect } from 'react-redux';

export function KeyDisplay({ keyProp }) {
  return (
    <div>The key is {keyProp}</div>
  );
}

export default connect((state) => { keyProp: state.key })(KeyDisplay);

然后在 reduce 的单元测试中,您可以只导入 key 的 reducer 并完全独立于用户界面进行测试:

keyReducer.test.js

import test from 'tape';
import { key } from './reducers.js';

test('key reducer', (t) => {
  t.plan(1);
  const output = key('old', { type: 'SET_VAL', value: 'new' });
  t.equal(output, 'new', 'SET_VAL should override old value');
});

此外,由于connect 将状态作为道具传递到组件中,因此您可以使用一些代表您感兴趣的状态的测试道具来渲染 unconnected 组件,而无需设置商店和提供者:

KeyDisplay.test.js

import test from 'tape';
import { renderIntoDocument } from 'react-addons-test-utils';
import { KeyDisplay } from './KeyDisplay.js';

test('KeyDisplay', (t) => {
  const component = renderIntoDocument(<KeyDisplay keyProp="test" />);
  // test component
});

【讨论】:

  • 太棒了,谢谢。既然你在redux 方面做得很好,我想知道你是否也可以看看this 问题。我觉得我并没有真正得到令人满意的解决方案。
  • 我必须同意 Dan 的观点,我也会这样做。如果你对 Redux 的不同场景有更深层次的问题,我绝对建议你与 Dan 联系,毕竟他确实创建了这个库;)
猜你喜欢
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
  • 2016-07-14
  • 1970-01-01
  • 2018-08-05
  • 2021-05-20
  • 1970-01-01
相关资源
最近更新 更多