简体   繁体   English

反应redux redux-saga的集成测试

[英]integration tests for react redux redux-saga

I have a project structure like this: 我有这样的项目结构:

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

so I have no problem with unit test with this structure, but I'm pretty confused as to how to structure integration test. 所以我对使用这种结构的单元测试没有任何问题,但我对如何构建集成测试感到困惑。 For my unit tests I am exporting each scene component as a class 对于我的单元测试,我将每个场景组件导出为一个类

export class SomeComponent extends Component {}

and as a redux connected component 并作为redux连接组件

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(SomeComponent)

So for the fist style of export (the class) I am unit testing it, but for the second way (the connected component way) I am unsure how to approach this specifically how to do integration testing in react/redux. 因此,对于第一种导出方式(类)我是单元测试它,但对于第二种方式(连接组件方式),我不确定如何具体如何在react / redux中进行集成测试。 I've searched the internet about this, but nothing that is close to this structure. 我在互联网上搜索了这个,但没有任何接近这个结构。

So: 所以:

  1. is integration testing in react/redux/middleware (in this case redux saga) how one component integrates with redux and middleware. 是react / redux / middleware(在这种情况下是redux saga)中的集成测试,一个组件如何与redux和中间件集成。
  2. Or is it about how the whole app works with all the components mounted? 或者它是关于整个应用程序如何与所有安装的组件一起工作?
  3. if it's #1 does that mean each component should have a single integration test file that tests how the component integrates with redux and middleware or if it's #2 then is it one test file that tests all components as one app? 如果它是#1这意味着每个组件应该有一个集成测试文件,测试组件如何与redux和中间件集成,或者如果它是#2那么它是一个测试文件,测试所有组件作为一个应用程序?

also, if it's #1 then how should I test routes via react router? 另外,如果它是#1那么我应该如何通过反应路由器测试路由?

In the case of your example, what we do is export mapStateToProps and mapDispatchToProps and we write unit tests for those (when they are not trivial). 在你的例子中,我们做的是导出mapStateToPropsmapDispatchToProps ,我们为那些编写单元测试(当它们不是微不足道的时候)。

I suppose you already unit test your action creators, sagas and reducers on their own. 我想你已经自己单独测试了你的动作创造者,传奇和减速器。

What's left as far as integration goes? 整合到底还剩下什么? You might want to mount the components in the context of a real store, to see if they react correctly to mutations of the redux store and whether they dispatch the correct actions or not. 您可能希望在真实存储的上下文中安装组件,以查看它们是否对redux存储的突变做出了正确的反应,以及它们是否分派了正确的操作。 In my project, we use end-to-end browser automation tests to verify things like this. 在我的项目中,我们使用端到端浏览器自动化测试来验证这样的事情。

If you want to write integration tests, consider writing UI tests for your app that will do full end to end testing. 如果您想编写集成测试,请考虑为您的应用程序编写UI测试,以进行完整的端到端测试。 There are many web options: 有很多网页选项:

or React Native: 或反应原生:

As for unit testing, you should be able to do that on a file by file basis without having to export the whole component. 至于单元测试,您应该能够逐个文件地执行此操作,而无需导出整个组件。 See the redux saga unit testing example: https://github.com/redux-saga/redux-saga/blob/master/docs/advanced/Testing.md 请参阅redux saga单元测试示例: https//github.com/redux-saga/redux-saga/blob/master/docs/advanced/Testing.md

Ok this is one way to test your components that use Redux. 好的,这是测试使用Redux的组件的一种方法。 Using storybook to demonstrate. 用故事书来演示。
First you need to accept the initial state when you are configuring the store: 首先,在配置存储时需要接受初始状态:

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;

This way you can inject your initial state to test some specific cases. 这样您就可以注入初始状态来测试某些特定情况。
Now in order to test the user interactions, you need to dispatch the actions the user can execute, and then verify the state of your components. 现在,为了测试用户交互,您需要调度用户可以执行的操作,然后验证组件的状态。
See this example: 看这个例子:

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;
    });

Also you can execute several actions, to get the result you want. 您还可以执行多个操作,以获得所需的结果。
eg 例如

        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
        });

And then verify the result: 然后验证结果:

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

For reference see this example project , see the Specifications tab to validate the tests: 有关参考,请参阅此示例项目 ,请参阅规范选项卡以验证测试:
在此输入图像描述

Here I'm using storybook to demostrate, but you can also do the same with simple mocha. 在这里我使用故事书进行演示,但你也可以用简单的摩卡语做同样的事情。
Hope this help. 希望这有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM