React Native单元测试--Jest+Enzyme+storybook

React Native的单元测试Jest+Enzyme+storybook

demo

配置

Jest配置

Jest

1. 安装

Jest在React Native利用react-native init AwesomeProject创建项目的时候就会默认安装了,这里就不多介绍了。

在你使用 create-react-appreact-native init 创建你的 React 或 React Native 项目时,Jest 都已经被配置好并可以使用了。在 __tests__文件夹下放置你的测试用例,或者使用 .spec.js.test.js 后缀给它们命名。不管你选哪一种方式,Jest 都能找到并且运行它们。

Enzyme配置

Enzyme

1. 安装
yarn add enzyme enzyme-adapter-react-16 --dev

每个适配器可能还有其他的对等体依赖关系,您也需要安装它们。举例来说, enzyme-adapter-react-16对应用同版本的依赖react@16react-dom@16react-test-renderer@16

2. 初始化配置

由于React Native有很多环境依赖性,如果没有主机设备,很难模拟。所以还需要添加react-native-mock,如下

yarn add react-native-mock --dev
3. 初始化配置

做后需要配置enzyme的适配器,一个一般要根据react的版本配置,现在项目中用的是react@16,所以如下配置

import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import 'react-native-mock/mock';

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

还需要让此配置,在所以test之前执行,进行如下设置

// package.json
// ...
"jest": {
    // ...
    "setupFiles": [
      "/__tests__/Setup"
    ]
  }
// ...

Storybook配置

Storybook

1. 安装

执行下面三条指令就能完成安装

cd my-project-directory
npm i -g @storybook/cli
getstorybook
2. 运行
npm run storybook

运行

Jest 运行

  1. 运行全部测试用例

    npm jest
    
  2. 运行单个测试用例,可以借助webstorm工具,来运行,非常方便

    React Native单元测试--Jest+Enzyme+storybook_第1张图片
    image

Storybook运行

  1. 在开发组件的时候要把storybook运行起来,并写stories

    npm run storybook
    

用例

Jest 常用api用法实例

中文 英文
匹配器 Matchers
测试异步代码 Asynchronous
模拟器 Mock Functions
全局函数 Global Functions

API集合

全局方法
  • afterAll(fn, timeout)
  • afterEach(fn, timeout)
  • beforeAll(fn, timeout)
  • beforeEach(fn, timeout)
  • describe(name, fn)
  • describe.each(table)(name, fn)
  • describe.only(name, fn)
  • describe.only.each(table)(name, fn)
  • describe.skip(name, fn)
  • describe.skip.each(table)(name, fn)
  • require.requireActual(moduleName)
  • require.requireMock(moduleName)
  • test(name, fn, timeout)
  • test.each(table)(name, fn)
  • test.only(name, fn, timeout)
  • test.only.each(table)(name, fn)
  • test.skip(name, fn)
  • test.skip.each(table)(name, fn)
匹配器
  • expect(value)
  • expect.extend(matchers)
  • expect.anything()
  • expect.any(constructor)
  • expect.arrayContaining(array)
  • expect.assertions(number)
  • expect.hasAssertions()
  • expect.not.arrayContaining(array)
  • expect.not.objectContaining(object)
  • expect.not.stringContaining(string)
  • expect.not.stringMatching(string | regexp)
  • expect.objectContaining(object)
  • expect.stringContaining(string)
  • expect.stringMatching(string | regexp)
  • expect.addSnapshotSerializer(serializer)
  • .not
  • .resolves
  • .rejects
  • .toBe(value)
  • .toHaveBeenCalled()
  • .toHaveBeenCalledTimes(number)
  • .toHaveBeenCalledWith(arg1, arg2, ...)
  • .toHaveBeenLastCalledWith(arg1, arg2, ...)
  • .toHaveBeenNthCalledWith(nthCall, arg1, arg2, ....)
  • .toHaveReturned()
  • .toHaveReturnedTimes(number)
  • .toHaveReturnedWith(value)
  • .toHaveLastReturnedWith(value)
  • .toHaveNthReturnedWith(nthCall, value)
  • .toBeCloseTo(number, numDigits)
  • .toBeDefined()
  • .toBeFalsy()
  • .toBeGreaterThan(number)
  • .toBeGreaterThanOrEqual(number)
  • .toBeLessThan(number)
  • .toBeLessThanOrEqual(number)
  • .toBeInstanceOf(Class)
  • .toBeNull()
  • .toBeTruthy()
  • .toBeUndefined()
  • .toContain(item)
  • .toContainEqual(item)
  • .toEqual(value)
  • .toHaveLength(number)
  • .toMatch(regexpOrString)
  • .toMatchObject(object)
  • .toHaveProperty(keyPath, value)
  • .toMatchSnapshot(propertyMatchers, snapshotName)
  • .toStrictEqual(value)
  • .toThrow(error)
  • .toThrowErrorMatchingSnapshot()

Enzyme 常用api用法实例

enzyme有3种渲染方式:rendermountshallow,先了解下区别。

rendermountshallow的区别

render采用的是第三方库Cheerio的渲染,渲染结果是普通的html结构,对于snapshot使用render比较合适。

shallow和mount对组件的渲染结果不是html的dom树,而是react树,如果你chrome装了react devtool插件,他的渲染结果就是react devtool tab下查看的组件结构,而render函数的结果是element tab下查看的结果。

这些只是渲染结果上的差别,更大的差别是shallow和mount的结果是个被封装的ReactWrapper,可以进行多种操作,譬如find()、parents()、children()等选择器进行元素查找;state()、props()进行数据查找,setState()、setprops()操作数据;simulate()模拟事件触发。

shallow只渲染当前组件,只能能对当前组件做断言;mount会渲染当前组件以及所有子组件,对所有子组件也可以做上述操作。一般交互测试都会关心到子组件,我使用的都是mount。但是mount耗时更长,内存啥的也都占用的更多,如果没必要操作和断言子组件,可以使用shallow。

交互测试

主要利用simulate()接口模拟事件,实际上simulate是通过触发事件绑定函数,来模拟事件的触发。触发事件后,去判断props上特定函数是否被调用,传参是否正确;组件状态是否发生预料之中的修改;某个dom节点是否存在是否符合期望。

官方api
  • .find(selector) => ShallowWrapper

  • .findWhere(predicate) => ShallowWrapper

  • .filter(selector) => ShallowWrapper

  • .filterWhere(predicate) => ShallowWrapper

  • .hostNodes() => ShallowWrapper

  • .contains(nodeOrNodes) => Boolean

  • .containsMatchingElement(node) => Boolean

  • .containsAllMatchingElements(nodes) => Boolean

  • .containsAnyMatchingElements(nodes) => Boolean

  • .equals(node) => Boolean

  • .matchesElement(node) => Boolean

  • .hasClass(className) => Boolean

  • .is(selector) => Boolean

  • .exists() => Boolean

  • .isEmpty() => Boolean

  • .isEmptyRender() => Boolean

  • .not(selector) => ShallowWrapper

  • .children() => ShallowWrapper

  • .childAt(index) => ShallowWrapper

  • .parents() => ShallowWrapper

  • .parent() => ShallowWrapper

  • .closest(selector) => ShallowWrapper

  • .shallow([options\]) => ShallowWrapper

  • .render() => CheerioWrapper

  • .unmount() => ShallowWrapper

  • .text() => String

  • .html() => String

  • .get(index) => ReactElement

  • .getNode() => ReactElement

  • .getNodes() => Array

  • .at(index) => ShallowWrapper

  • .first() => ShallowWrapper

  • .last() => ShallowWrapper

  • .state([key\]) => Any

  • [.context([key\]) => Any](http://airbnb.io/enzyme/docs/api/ShallowWrapper/context.html

  • .props() => Object

  • .prop(key) => Any

  • .key() => String

  • .simulate(event[, data\]) => ShallowWrapper

  • .setState(nextState) => ShallowWrapper

  • .setProps(nextProps) => ShallowWrapper

  • .setContext(context) => ShallowWrapper

  • .instance() => ReactComponent

  • .update() => ShallowWrapper

  • .debug() => String

  • .type() => String|Function

  • .name() => String

  • .forEach(fn) => ShallowWrapper

  • .map(fn) => Array

  • .reduce(fn[, initialValue\]) => Any

  • .reduceRight(fn[, initialValue\]) => Any

  • .slice([begin[, end\]]) => ShallowWrapper

  • .tap(intercepter) => Self

  • .some(selector) => Boolean

  • .someWhere(predicate) => Boolean

  • .every(selector) => Boolean

  • .everyWhere(predicate) => Boolean

  • .dive([options]) => ShallowWrapper

组件测试

  1. 用storybook做组件测试,既可以存储组件快照,也可以快速查看组件样式

    例如:

    // 
    import React from 'react';
    import { storiesOf } from '@storybook/react-native';
    import { action } from '@storybook/addon-actions';
    import { linkTo } from '@storybook/addon-links';
    import * as img from './img';
    
    import ImageButton from './ImageButton';
    
    storiesOf('', module)
      .add('normal', () =>
        
      )
      .add('cancel', () =>
        
      )
    ;
    
  2. 效果图如下


    React Native单元测试--Jest+Enzyme+storybook_第2张图片
    image
    React Native单元测试--Jest+Enzyme+storybook_第3张图片
    image
    React Native单元测试--Jest+Enzyme+storybook_第4张图片
    image
    React Native单元测试--Jest+Enzyme+storybook_第5张图片
    image
  3. 根据组件的需要,进行一些函数的测试,如下

    // imageButton.test.js
    import 'react-native'
    import React from 'react';
    import { mount, shallow } from 'enzyme';
    import ImageButton from '../../src/components/ImageButton';
    
    test('', () => {
      let i = 0
      const onPress = () => I++
      const wrapper = shallow();
      expect(wrapper.instance().props.title).toBe('1'); // uses the right handler
      expect(wrapper.prop('onPress')).toBe(onPress)
      expect(i).toBe(0);
      wrapper.simulate('press');
      expect(i).toBe(1);
    });
    

API测试

  1. API测试主要进行,返回状态码(200、500、502等)的验证,必要字段的返回,指定参数传入指定数据返回等验证,API测试可以在和后台定义接口的时候就写,等后台接口写好后直接跑一下测试用例就可验证。

    describe('api', () => {
    // ...
      test('/api/config', () => {
        expect.assertions(1); // 异步断言数量
        const param = Object.assign(defaultParam, {});
        const path = '/api/config';
        return api.post(path, param)
          .then(response => response.data)
          .then(response => {
            expect(response.errorCode).toBe(200);
          })
      });
    // ....
    
    });
    

参考文档

Engine单元测试调研文档

你可能感兴趣的:(React Native单元测试--Jest+Enzyme+storybook)