Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

年轻时,我不写单元测试 #16

Open
z2014 opened this issue Dec 15, 2018 · 0 comments
Open

年轻时,我不写单元测试 #16

z2014 opened this issue Dec 15, 2018 · 0 comments

Comments

@z2014
Copy link
Owner

z2014 commented Dec 15, 2018

在一个多人协作的大型项目中,我们在开发的过程中可能经常会面临到这样的问题:

  • 哎,这次我没有改动到这里啊,这怎么会有bug呢
  • 哎,怎么新加了个功能原来的功能受影响了呢
  • 哎,这里的样式为什么乱掉了

当我们被提出这些bug的时候,我们是二脸懵逼的,因为这不符合一个程序员的预期!!!
那么我们如何能够避免以上的问题,从而将经历投入到更多的开发(写bug)中去呢?
笔者在这里试着归纳了一下解决问题的办法

样式问题需要制定相应的规范

  • 不能使用css,只能用less来书写(大哥,都2888年了还不用less吗)
  • 使用less的类模块化写法
  • 命名风格采用BEM

(推荐)

.app{
    width: 100%;
    .center{
        height: 100%
    }
}

(不推荐)

.app{
    width: 100%;
}
.center{
    height: 100%
}

原有功能的可用性呢?

其实之前就已经简单的了解过了单元测试,但当时对于单元测试我是持有一种很否定的态度的,因为他太过于鸡肋,都是测试一些很基础的功能,但是当笔者被这次重构折磨之后,有重新思考了下如何能够保证代码的健壮性,抱着这个态度,笔者又去调研了下单元测试到底能够做什么。

再说它能够做什么之前,我们先来说说它是什么?

从字面解析来看,那就是把你的代码,拆分成一个一个的单元,然后针对不同的单元,编写不同的测试用例。

那这时候我们就会有一个问题了,那如果单元测试通过了,那到底能不能就不需要测试同学再测试就直接上线了呢?

按照我们的理想情况,如果我们的测试用例覆盖率达到了5个9以上,那应该是可以直接发布了,但是这个时候其实我们的内心还是会有一些疑虑,就是,那一个一个的模块都已经通过了,那集成在一起会不会有问题呢?这其实也是笔者到现在还不确定的问题。(获取集成测试能够解决?如果你已经有了答案,欢迎下方指正)

基于此,笔者希望在前端编写测试用例能够实现以下的目标:

  • 先保证一个一个的模块基础功能正常
  • 增加新功能时,原有功能不受影响

本着实现以上的要求,笔者下来介绍下具体的使用,关于不同测试框架的重点,这篇文章就不详细展开了,最终结合我们的项目,最终采用了facebook的jest+enzyme。重点将展开以下两种react组件类型测试。

展示型组件测试

展示型组件测试,意思就是要确保每一次的修改都是符合预期的,这里笔者要着重介绍下jest框架里面的snapshot功能。

shapshot就是会对组件进行一次快照记录当前的状态,每一次run jest的时候,对比上一次,看看是否有变化。那最完美的情况就是,我们将所有的css样式打包,然后渲染出组件ui,对比上一次的纪录,看看是否有修改,但是很可惜,目前shapshot生成的快照文件里面只有class,并没有相关样式,除非你把所有样式写成style内联,那么他就能记录下你的style样式。看似好像没有达到我们的目标。

但是仔细想想,这其实就违背了我们单元测试的初衷,笔者这里也大胆猜测下,jest官方在实现这个功能的时候,应该也只是想记录下一步一步的事件后,当前组件的html结构,对比上一次的快照,来看功能是否符合预期。代码的话比较简单:

describe('XJLayerCard', () => {
    it('renders correctly', () => {
        const wrapper = Enzyme.render(<XJLayerCard {...mockData}/>);
        expect(toJson(wrapper)).toMatchSnapshot();
    })
})

功能型组件测试

功能性组件测试,就是要覆盖到一个组件的基础功能,能够确保每一个修改之后,跑完单元测试,能够确定之前的功能正常。

一开始我觉得单元测试很鸡肋的原因也是没有深入了解它,这次发现就算是和业务结合很紧密的组件,也能够模拟正常的操作,这里就贴一个和redux结合的组件来举例

import React from 'react';
import Enzyme from 'enzyme';
import AppInput from '../AppInput';
import toJson from 'enzyme-to-json'
import initialStore from '@/../__mocks__/store.js';
import appInfoData from '@/../__mocks__/appInfo.js'
import { Provider } from 'react-redux';
import configureStore from '@/entries/maker/redux/store';
import { updateAppInfo } from '@/entries/maker/redux/action';
import moxios from 'moxios';
import instance from '@/api/instance'
import Adapter from 'enzyme-adapter-react-16';
Enzyme.configure({ adapter: new Adapter() });

let store;
let wrapper;
beforeEach(() => {
    moxios.install(instance);
    store = configureStore(initialStore)
    wrapper = Enzyme.mount(
        <Provider store={store}>
            <AppInput onChange={(obj) => {
                store.dispatch(updateAppInfo(obj))
            }}/>
        </Provider>
    )
})
afterEach(function () {
    moxios.uninstall(instance);
})
describe('demo', () => {

    it('renders correctly', () => {
        expect(toJson(wrapper)).toMatchSnapshot();
    });

    it('click div, select show', () => {
        // 渲染选项框正常
        expect(wrapper.find('.xj-appinput-item').length).toEqual(2);
        // 一开始没有输入框
        expect(wrapper.find('input').length).toEqual(0);
        wrapper.find('.xj-appinput-value-wrapper').at(0).simulate('click');
        expect(wrapper.find('input').length).toEqual(1);
    });

    it('updateAppInfo action', (done) => {
        // 拦截请求
        moxios.stubRequest('/app/get', {
            status: 200,
            responseText: 'success'
        });
        // 点击下拉框中的第一个,会触发action
        wrapper.find('.xj-appinput-item').at(0).simulate('click');
        moxios.wait(() => {
            // mock数据
            let request = moxios.requests.mostRecent();
            request.respondWith({
                status: 200,
                response: appInfoData
            }).then((res) => {
                // input输入框消失
                expect(wrapper.find('input').length).toEqual(0);
                // 选中的app展示出来
                expect(wrapper.find('.xj-appinput-wrapper').length).toEqual(1);
                expect(toJson(wrapper)).toMatchSnapshot();
                done();
            }).catch(err => {
                console.log(err)
            })
        });
    })


})

可以看到,这里的测试内容是结合了redux,axios库。那其实整个流程就是初始化这个组件,看看渲染的html结构是否符合预期,然后点击下拉框,选中其中第一个,发起请求,拉回详细数据,再观察组件是否展示正常,编写完测试用例后,就已经用代码模拟了整个手工操作,怎么样,是不是很强大?

@z2014 z2014 changed the title 用jest来测试你的react应用 年轻时,我不写单元测试。。。 Dec 15, 2018
@z2014 z2014 changed the title 年轻时,我不写单元测试。。。 年轻时,我不写单元测试 Dec 15, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant