react native+redux 使用jest进行unit test

react native添加单元测试中的库

测试代码的当前版本是

"react": "16.0.0",
"react-native": "^0.48.4",
"react-redux": "^5.0.6",
"redux": "^3.7.2",
"redux-logger": "^2.7.4",
"redux-thunk": "2.2.0",

因为现在的react native很多都会使用redux,所以测试中有针对这部分的内容。
需要用到的库

"babel-jest": "19.0.0",
"babel-polyfill": "^6.26.0",
"babel-preset-react-native": "1.9.1",
"chai": "^4.1.2",
"chai-as-promised": "^7.1.1",
"chai-enzyme": "^1.0.0-beta.0",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"jest": "19.0.2",
"react-dom": "^16.2.0",
"react-test-renderer": "15.4.2",
"redux-mock-store": "^1.4.0",
"sinon": "^4.1.6",
"sinon-chai": "^2.14.0"

chai-enzyme 在默认安装的时候版本号是0.8.0,这个版本不能兼容到”enzyme”: “^3.3.0”,需要使用最新的1.0.0-beta.0版本

jest的配置

"jest": {
    "preset": "react-native",
    "transform": {
        "^.+\\.jsx?$": "babel-jest"
    }
}

jest加入 transform的 babel-jest配置是为了避免出现jest不能识别es6的import等关键字。

待测组件代码

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

import { Actions } from 'react-native-router-flux';
import * as profileActions from '../modules/users/reducers/profileActions';

import React, { Component } from 'react';
import {
    View,
    Text,
    TouchableOpacity,
} from 'react-native';

function mapStateToProps(state) {
    return {
        profile: state.profile
    };
};

function mapDispatchToProps(dispatch) {
    return {
        actions: bindActionCreators({ ...profileActions }, dispatch)
    };
}

export class TestView extends Component {
    constructor(props) {
        super(props);

    }

    render() {
        try {
            let userNameControl;
            if (this.props.username) {
                userNameControl = <Text>this.props.username</Text>
            }
            return (
                <View style={{
                    backgroundColor: 'white', flexGrow: 1,
                    alignItems: 'center', justifyContent: 'center'
                }}>
                    <TouchableOpacity style={styles.Button} onPress={() => {
                        this.props.actions.getProfile();
                    }}>
                        <Text style={{ color: 'white' }}>Get Profile</Text>
                    </TouchableOpacity>
                    {userNameControl}
                </View>
            );
        } catch (error) {
            return <View></View>
        }

    }
}


let styles = {
    Button: {
        alignItems: 'center', justifyContent: 'center',
        backgroundColor: '#286090',
        padding: 10,
        borderRadius: 5
    }
}


export default connect(mapStateToProps, mapDispatchToProps)(TestView);

需要注意的代码是
export class TestView extends Component
上面这行是为了不去引入redux,而在接下来的测试代码中自己来引入props的数据。
export default connect(mapStateToProps, mapDispatchToProps)(TestView);
如果用上面这行代码创建的class测试就需要去创建store,引用sense等组件,实在太过麻烦。

测试代码
import React from 'react'
import { bindActionCreators } from 'redux'
import { TestView } from '../TestView'
import {
    View,
    Text,
    TouchableOpacity
} from 'react-native'

require('babel-polyfill')

import { configure } from 'enzyme'

import Adapter from 'enzyme-adapter-react-16'

import sinon from 'sinon'
import chai from 'chai'
import sinonChai from 'sinon-chai'
import chaiAsPromised from 'chai-as-promised'
import chaiEnzyme from 'chai-enzyme'

chai.use(sinonChai)
chai.use(chaiAsPromised)
chai.use(chaiEnzyme())

global.chai = chai
global.sinon = sinon
global.expect = chai.expect
global.should = chai.should()

configure({ adapter: new Adapter() });

import ReactTestUtils from 'react-dom/test-utils';
import { shallow } from 'enzyme'


describe('TestView', () => {
    let _props, _spies, _wrapper
    let eventCodeControlProps = {
        global: {
            language: {
                EventCodeEmpty: 'test',
                OK: 'OK',
                EventCodePlaceHolder: 'EventCodePlaceHolder',
                EventCode: 'EventCode',
                PromoCode: 'PromoCode'
            }
        }
    }

    beforeEach(() => {
        _spies = {}
        _props = {
            ...eventCodeControlProps,
            actions: bindActionCreators({
                getProfile: (_spies.getProfile = sinon.spy())
            }, _spies.dispatch = sinon.spy())
        };


        _wrapper = shallow(<TestView {..._props} />);
    })

    it('Should has one View.', () => {
        expect(_wrapper.is('View')).to.equal(true);
    })

    it('Should has one children.', () => {
        expect(_wrapper.children()).to.have.length(1);
    })

    it('Each element of form should be <TouchableOpacity>.', () => {
        _wrapper.children().forEach(function (node) {
            expect(node.is(TouchableOpacity)).to.equal(true);
        })
    })

    it('Get and show username', () => {
        _spies = {}
        _props = {
            ...eventCodeControlProps,
            actions: bindActionCreators({
                getProfile: (_spies.getProfile = () => {
                    _wrapper.setProps({ username: '123' })
                })
            }, _spies.dispatch = sinon.spy())
        };


        _wrapper = shallow(<TestView {..._props} />);
        let to = _wrapper.find('TouchableOpacity');
        to.simulate('press');
        expect(_wrapper.children()).to.have.length(2);

    })
})

最后一个测试用例复杂一些,可以测试按钮的点击动作。

to.simulate(‘press’);

会触发TouchableOpacity控件的onPress事件。onPress事件调用的函数中调用了

this.props.actions.getProfile();

这个函数则在

 _props = {
    ...eventCodeControlProps,
    actions: bindActionCreators({
         getProfile: (_spies.getProfile = () => {
             _wrapper.setProps({ username: '123' })
        })
    }, _spies.dispatch = sinon.spy())
};

中做了mock。接下来的

_wrapper.setProps({ username: ‘123’ })

会触发控件的render函数。

this.props.username === ‘123’

userNameControl就会显示出来

expect(_wrapper.children()).to.have.length(2);

子组件就会变成两个。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值