Redux:如何测试连接的组件?

IT技术 unit-testing reactjs redux enzyme
2021-04-24 01:18:50

我正在Enzyme对我的 React 组件进行单元测试。我知道为了测试未连接的原始组件,我必须将其导出并进行测试(我已经这样做了)。我已经设法为连接的组件编写了一个测试,但我真的不确定这是否是正确的方法,以及我想要测试的连接组件究竟是什么。

容器.jsx

import {connect} from 'react-redux';
import Login from './Login.jsx';
import * as loginActions from './login.actions';

const mapStateToProps = state => ({
  auth: state.auth
});
const mapDispatchToProps = dispatch => ({
  loginUser: credentials => dispatch(loginActions.loginUser(credentials))

});
export default connect(mapStateToProps, mapDispatchToProps)(Login);

容器.test.js

import React from 'react';
import {Provider} from 'react-redux';
import {mount, shallow} from 'enzyme';
import {expect} from 'chai';
import LoginContainer from '../../src/login/login.container';
import Login from '../../src/login/Login';


describe('Container Login', () => {
  it('should render the container component', () => {
    const storeFake = state => ({
      default: () => {
      },
      subscribe: () => {
      },
      dispatch: () => {
      },
      getState: () => ({ ...state })
    });
    const store = storeFake({
      auth: {
        sport: 'BASKETBALL'
      }
    });

    const wrapper = mount(
      <Provider store={store}>
        <LoginContainer />
      </Provider>
    );

    expect(wrapper.find(LoginContainer).length).to.equal(1);
    const container = wrapper.find(LoginContainer);
    expect(container.find(Login).length).to.equal(1);
    expect(container.find(Login).props().auth).to.eql({ sport: 'BASKETBALL' });
  });
});
3个回答

这是个有趣的问题。

我通常会同时导入容器和组件来进行测试。对于我使用的容器测试,redux-mock-store. 组件测试用于测试异步功能。例如,在您的情况下,登录过程是使用sinon存根的异步函数这是相同的片段,

import React from 'react';
import {Provider} from 'react-redux';
import {mount, shallow} from 'enzyme';
import {expect} from 'chai';
import LoginContainer from '../../src/login/login.container';
import Login from '../../src/login/Login';
import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { stub } from 'sinon';

const mockStore = configureMockStore([thunk]);

describe('Container Login', () => {
  let store;
  beforeEach(() => {
    store = mockStore({
      auth: {
        sport: 'BASKETBALL',
      },
    });
  });
  it('should render the container component', () => {
    const wrapper = mount(
      <Provider store={store}>
        <LoginContainer />
      </Provider>
    );

    expect(wrapper.find(LoginContainer).length).to.equal(1);
    const container = wrapper.find(LoginContainer);
    expect(container.find(Login).length).to.equal(1);
    expect(container.find(Login).props().auth).to.eql({ sport: 'BASKETBALL' });
  });

  it('should perform login', () => {
    const loginStub = stub().withArgs({
      username: 'abcd',
      password: '1234',
    });
    const wrapper = mount(<Login
      loginUser={loginStub}
    />);
  wrapper.find('button').simulate('click');
  expect(loginStub.callCount).to.equal(1);
  });
});

正如您所指出的,我通常这样做的方法是也导出未连接的组件,然后对其进行测试。

IE

export {Login};

这是一个例子。组件的源,和测试的源

对于包装的组件,我不会为那些编写测试,因为我的映射(mapStateToPropsmapDispatchToProps)通常非常简单。如果我想测试一个包装的组件,我真的只是在测试这些地图。所以这些是我会选择显式测试的内容,而不是以包装形式重新测试整个组件。

有两种方法可以测试这些功能。一种方法是导出module本身内的函数。

IE;

export {mapStateToProps, mapDispatchToProps}

我不是这个的忠实粉丝,因为我不希望应用程序中的其他module访问它们。在我的测试中,我有时会使用babel-plugin-rewire来访问“范围内”变量,所以这就是我在这种情况下会做的。

这可能看起来像:

import {
  Login, __Rewire__
}

const mapStateToProps = __Rewire__.__get__('mapStateToProps');

describe('mapStateToProps', () => { ... });

如果我们有路由器问题,我们可以考虑将路由器库添加到测试文件中,例如:

import React from 'react';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import { mount } from 'enzyme';
import ReadDots from './ReadDots';

const storeFake = state => ({
  default: () => {
  },
  subscribe: () => {
  },
  dispatch: () => {
  },
  getState: () => ({ ...state })
});

const store = storeFake({
  dot: {
    dots: [
      {
        id: '1',
        dot: 'test data',
        cost: '100',
        tag: 'pocket money'
      }
    ]
  }
});

describe('<ReadDots />', () => {
  it('should render ReadDots component', () => {
    const component = mount(
      <Provider store={store}>
        <Router>
          <ReadDots />
        </Router>
      </Provider>
    );
    expect(component.length).toEqual(1);
  });
});