reactjs-如何对React-Redux连接的组件进行单元测试?

我正在使用Mocha,Chai,Karma,Sinn,Webpack进行单元测试。

我按照此链接为React-Redux Code配置了我的测试环境。

如何在React with Karma,Babel和Webpack上实现测试+代码覆盖率

我可以成功地测试动作和reducers的javascript代码,但是在测试我的组件时,它总是会抛出一些错误。

import React from 'react';
import TestUtils from 'react/lib/ReactTestUtils'; //I like using the Test Utils, but you can just use the DOM API instead.
import chai from 'chai';
// import sinon from 'sinon';
import spies from 'chai-spies';

chai.use(spies);

let should = chai.should()
  , expect = chai.expect;

import { PhoneVerification } from '../PhoneVerification';

let fakeStore = {
      'isFetching': false,
      'usernameSettings': {
        'errors': {},
        'username': 'sahil',
        'isEditable': false
      },
      'emailSettings': {
        'email': 'test@test.com',
        'isEmailVerified': false,
        'isEditable': false
      },
      'passwordSettings': {
        'errors': {},
        'password': 'showsomestarz',
        'isEditable': false
      },
      'phoneSettings': {
        'isEditable': false,
        'errors': {},
        'otp': null,
        'isOTPSent': false,
        'isOTPReSent': false,
        'isShowMissedCallNumber': false,
        'isShowMissedCallVerificationLink': false,
        'missedCallNumber': null,
        'timeLeftToVerify': null,
        '_verifiedNumber': null,
        'timers': [],
        'phone': '',
        'isPhoneVerified': false
      }
}

function setup () {
    console.log(PhoneVerification);
    // PhoneVerification.componentDidMount = chai.spy();
    let output = TestUtils.renderIntoDocument(<PhoneVerification {...fakeStore}/>);
    return {
        output
    }
}

describe('PhoneVerificationComponent', () => {
    it('should render properly', (done) => {
        const { output } = setup();
        expect(PhoneVerification.prototype.componentDidMount).to.have.been.called;
        done();
    })
});

上面的代码出现了以下错误。

FAILED TESTS:
  PhoneVerificationComponent
    ✖ should render properly
      Chrome 48.0.2564 (Mac OS X 10.11.3)
    Error: Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.

尝试从正宗间谍转换为亲密间谍。

我应该如何对我的React-Redux Connected Components(Smart Components)进行单元测试?

Ayushya asked 2020-06-21T06:52:58Z
4个解决方案
47 votes

一种更漂亮的方法是同时导出您的普通组件和包裹在connect中的组件。 命名的export将是组件,默认是包装的组件:

export class Sample extends Component {

    render() {
        let { verification } = this.props;
        return (
            <h3>This is my awesome component.</h3>
        );
    }

}

const select = (state) => {
    return {
        verification: state.verification
    }
}

export default connect(select)(Sample);

这样,您可以正常导入应用程序,但是在测试时,可以使用import { Sample } from 'component'导入命名的导出。

Ashwin van Dijk answered 2020-06-21T06:53:17Z
14 votes

您可以测试连接的组件,我认为您应该这样做。 您可能要先测试未连接的组件,但我建议您先不测试已连接的组件,否则将无法获得完整的测试范围。

以下是未经测试的Redux和酶的提取物。 中心思想是使用Provider将测试中的状态连接到测试中已连接的组件。

import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import SongForm from '../SongForm'; // import the CONNECTED component

// Use the same middlewares you use with Redux's applyMiddleware
const mockStore = configureMockStore([ /* middlewares */ ]);
// Setup the entire state, not just the part Redux passes to the connected component.
const mockStoreInitialized = mockStore({ 
    songs: { 
        songsList: {
            songs: {
                songTags: { /* ... */ } 
            }
        }
    }
}); 

const nullFcn1 = () => null;
const nullFcn2 = () => null;
const nullFcn3 = () => null;

const wrapper = mount( // enzyme
        <Provider store={store}>
          <SongForm
            screen="add"
            disabled={false}
            handleFormSubmit={nullFcn1}
            handleModifySong={nullFcn2}
            handleDeleteSong={nullFcn3}
          />
        </Provider>
      );

const formPropsFromReduxForm = wrapper.find(SongForm).props(); // enzyme
expect(
        formPropsFromReduxForm
      ).to.be.deep.equal({
        screen: 'add',
        songTags: initialSongTags,
        disabled: false,
        handleFormSubmit: nullFcn1,
        handleModifySong: nullFcn2,
        handleDeleteSong: nullFcn3,
      });

===== ../SongForm.js

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

const SongForm = (/* object */ props) /* ReactNode */ => {
    /* ... */
    return (
        <form onSubmit={handleSubmit(handleFormSubmit)}>
            ....
        </form>

};

const mapStateToProps = (/* object */ state) /* object */ => ({
    songTags: state.songs.songTags
});
const mapDispatchToProps = () /* object..function */ => ({ /* ... */ });

export default connect(mapStateToProps, mapDispatchToProps)(SongForm)

您可能要使用纯Redux创建商店。 redux-mock-store只是用于测试的轻量级版本。

您可能要使用react-addons-test-utils而不是airbnb的酶。

我使用airbnb的chai酶来获得React感知的期望选项。 在此示例中不需要。

JohnSz answered 2020-06-21T06:53:55Z
7 votes

可接受的答案的问题在于,我们只是为了进行测试而不必要地导出了某些内容。 在我看来,导出类只是为了测试它不是一个好主意。

这是一个更整洁的解决方案,除了连接的组件外,无需导出任何内容:

如果使用的是笑话,则可以模拟jest.unmock('react-redux'))方法以返回三件事:

  1. mapStateToProps
  2. mapDispatchToProps
  3. 反应组件

这样做非常简单。 有两种方法:内联模拟或全局模拟。

1.使用内联模拟

在测试的describe函数之前添加以下代码段。

jest.unmock('react-redux'))

2.使用文件模拟

  1. 在根目录(package.json所在的位置)中创建文件jest.unmock('react-redux'))
  2. 在文件中添加以下代码段。

jest.unmock('react-redux'))

模拟之后,您将能够使用jest.unmock('react-redux'))Container.mapDispatchToPropsContainer.ReactComponent访问以上所有三个。

只需简单地导入容器即可

jest.unmock('react-redux'))

希望能帮助到你。

请注意,如果您使用文件模拟。 模拟文件将在所有测试用例中全局使用(除非在测试用例之前执行jest.unmock('react-redux'))

编辑:我写了一个详细的博客,上面详细解释了:

[HTTP://让阿虎了嘎巴.com/front-end/2018/10/19/unit-testing-热镀锌-containers-他和-better-蛙泳-using-jest.HTML]

Rahul Gaba answered 2020-06-21T06:55:43Z
1 votes

尝试创建2个文件,其中一个带有组件本身,不知道任何存储或任何内容(PhoneVerification-component.js)。 然后是第二个(PhoneVerification.js),它将在您的应用程序中使用,并且仅返回通过2932403342703854854592函数订阅存储的第一个组件,类似

import PhoneVerificationComponent from './PhoneVerification-component.js'
import {connect} from 'react-redux'
...
export default connect(mapStateToProps, mapDispatchToProps)(PhoneVerificationComponent)

然后,您可以通过在测试中要求PhoneVerification-component.js并提供必要的模拟道具来测试“哑”组件。 没有已经测试过的测试点(连接装饰器,mapStateToProps,mapDispatchToProps等)。

george.cz answered 2020-06-21T06:56:09Z
translate from https://stackoverflow.com:/questions/35131312/how-to-unit-test-react-redux-connected-components