react redux redux-saga

时间:2018-07-12 00:36:58

标签: reactjs redux react-redux integration-testing redux-saga

我有一个像这样的项目结构:

app/
  global/
    styles/
    components/
  scenes/
    Home/
      actions.js
      constants.js
      index.jsx
      reducer.js
      sagas.js
      styles.styl
      index.spec.jsx
    some-other-scene/
      actions.js
      constants.js
      index.jsx
      reducer.js
      sagas.js
      styles.styl
      index.spec.jsx

所以我对这种结构的单元测试没有问题,但是我对如何进行结构化集成测试感到很困惑。对于我的单元测试,我将每个场景组件导出为一个类

export class SomeComponent extends Component {}

并作为Redux连接的组件

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(SomeComponent)

因此,对于第一个导出样式(类),我对其进行单元测试,但是对于第二种方式(连接组件方式),我不确定如何具体实现此方法,如何在react / redux中进行集成测试。我已经在互联网上搜索了有关此内容的信息,但没有找到与之接近的信息。

所以:

  1. 是react / redux / middleware(在本例中为redux saga)中的集成测试,一个组件如何与redux和中间件集成。
  2. 还是整个应用程序如何在安装了所有组件的情况下工作?
  3. 如果是#1,这意味着每个组件都应该有一个集成测试文件来测试该组件如何与Redux和中间件集成,或者如果是#2,那么它是一个测试文件,可以将所有组件作为一个应用程序进行测试吗? li>

如果是#1,那我该如何通过React Router测试路由?

3 个答案:

答案 0 :(得分:1)

在您的示例中,我们要做的是导出mapStateToPropsmapDispatchToProps,并为它们编写单元测试(当它们不重要时)。

我想您已经对动作创建者,saga和reduce进行了单元测试。

到目前为止,集成还剩下什么?您可能希望将组件安装在实际存储的上下文中,以查看它们是否对redux存储的突变做出正确的反应,以及它们是否调度正确的操作。在我的项目中,我们使用端到端浏览器自动化测试来验证这样的事情。

答案 1 :(得分:0)

如果要编写集成测试,请考虑为您的应用编写UI测试,以进行完整的端到端测试。网络选项很多:

或React Native:

对于单元测试,您应该能够逐个文件地执行此操作,而不必导出整个组件。请参阅redux saga单元测试示例:https://github.com/redux-saga/redux-saga/blob/master/docs/advanced/Testing.md

答案 2 :(得分:0)

好的,这是测试使用Redux的组件的一种方法。用故事书来演示。
首先,在配置商店时,您需要接受初始状态:

import { createStore, applyMiddleware } from 'redux';
import rootReducer from './combineReducers';
import thunk from 'redux-thunk'; // In your case use saga

const ConfigureStore = (initialState) => {    
    let middleware = applyMiddleware(thunk);
    const store = initialState ?
        createStore(rootReducer, initialState, middleware)
        : createStore(rootReducer, middleware);
    return store;
};

export default ConfigureStore;

这样,您可以注入初始状态以测试某些特定情况。
现在,为了测试用户交互,您需要分派用户可以执行的操作,然后验证组件的状态。
请参见以下示例:

import React from 'react';
import configureStore from '../_setup';
import { storiesOf } from '@storybook/react';
import { Provider } from 'react-redux';
import { specs, describe, it } from 'storybook-addon-specifications'
import { configure,  mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import { expect } from 'chai';
import Greeting from '../components/Greeting';


let store = configureStore();// Here initializing the store, you can pass the initial state also.
configure({ adapter: new Adapter() });

storiesOf('Greetings with Redux', module)
    .add('User says hello', () => {
        // here you pass the store to the component
        const storyWithProvider = (
            <Provider store={store}>
                <Greeting />
            </Provider>
        );
        // Here you execute the action you want to test.
        store.dispatch({
            type: 'SayHelloAction',
            payload: 'Jhon Doe'
        });

        specs(() => describe('User says hello', function () {
            it('Should have greeting message with the user name', function () {
                const output = mount(storyWithProvider);
                // Here you verify the state of the component
                expect(output.text()).to.contains('Hello: Jhon Doe');
            });
        }));
        return storyWithProvider;
    });

您还可以执行一些操作,以获得所需的结果。
例如

        store.dispatch({
            type: constants.actions.SHOW_VENDOR_PRODUCTS,
            payload: selectedVendor
        });
        store.dispatch({
            type: constants.actions.VENDOR_ACCEPTS_ORDER,
            payload: false
        });
        store.dispatch({
            type: constants.actions.ADD_PRODUCT,
            payload: selectedProduct
        });

然后验证结果:

expect(wrapper.find('.btn .btn-lg .btn-success')).to.have.length.of(1);

有关参考,请参见此example project,请参见“规格”标签以验证测试:
enter image description here

在这里,我正在使用故事书进行演示,但是您也可以使用简单的摩卡咖啡来做同样的事情。
希望有帮助。