jest测试
笔者接触组件库开发已经几月了,目前组件库越做越大,越做越好,但随之而来接入的业务方提的bug也越来越多,这显得前端自动化测试格外重要,此文主要是讲测试入门以及一些思想,具体怎么配置笔者觉得没有必要花心思去整理,网上一搜一大堆。
测试类型
- 单元测试:又称模块测试,对一个模块、类、函数等进行正确性检验工作。目标是隔离程序部件并证明这些单个部件是正确的。一个单元测试提供了代码片断需要满足的严密的书面规约。因此,单元测试带来了一些益处。 单元测试在软件开发过程的早期就能发现问题。
- 功能测试:又称黑盒测试,是通过测试来检测每个功能是否都能正常使用。在测试中,把程序看作一个不能打开的黑盒子,在完全不考虑程序内部结构和内部特性的情况下,在程序接口进行测试,它只检查程序功能是否按照需求规格说明书的规定正常使用,程序是否能适当地接收输入数据而产生正确的输出信息。黑盒测试着眼于程序外部结构,不考虑内部逻辑结构,主要针对软件界面和软件功能进行测试。
- 集成测试:在单元测试的基础上,将所有模块按照设计要求组装成子系统或者系统,进行测试
- 冒烟测试: 在正式全面的测试之前,对主要功能进行的与测试,确认主要功能是否满足需要,软件是否能正常运行
jest匹配器
- toBe (===)
- toEqual
- toBeNull
- toBeTrusty
- toBeFalsy
- toBeGreaterThan(number)
- toBeGreaterThanOrEqual(number)
- toBeLessThan(number)
- toBeLessThanOrEqual(number)
- toBeCloseTo(number); // 近似
- toContainer
- toMatch可以检查字符串是否与正则表达式匹配
++jest –watchAll(类似热加载)++
1 | //toBe 失败 |
异步函数的测试
1 | export const fecthData = (fn) => { |
1 | //回调类型 |
expect.assertions(1); //至少要执行一个expect语法,expect.assertions,来测试一定数量的断言被调用,否则fulfilled态promise不会让测试失败
jest globals API
- discribe(name,func): 块,一个测试单元的所用果能测试用例可组合为一个块
- it(name,func,timeout): 测试用例,一般一个测试用例测试一个单一功能
beforeEach和afterEach
需要为多次测试重复设置的工作,可以使用breforeEach和afterEach。
1 | beforeEach(()=>{ |
beforeAll和afterAll
例如,如果 initializeCityDatabase 和 clearCityDatabase 都返回了 promise ,城市数据库可以在测试中重用,我们就能把我们的测试代码改成这样
1 | beforeAll(()=>{ |
全局和describe都拥有上面四个生命周期。
- 但describe的after函数优先级高于全局after函数
- describe的before函数优先级要低于全局的before函数
mock函数
1 | const func = jest.fn(); // mock函数,捕获函数的调用 |
mock函数中的作用
- 捕获函数的调用和返回结果,以及this和调用顺序(func.mock)
- 自由设置返回结 func.mockReturnValueOnce();
- 改变内部函数的实现
通过mock函数来测试异步函数
1 | export getData = ()=>{ |
1 | const func = jest.fn(); |
1 | jest.mock('./demo'); |
spyOn
jest.spuOn()
同样创建一个mock函数,但他比jest.fn()或jest.mock();更厉害的是,他还会执行被mock的原函数。例如
1 | const fn = function(){ |
snapshot 快照测试
就是看你生成的快照测试跟原来一不一样,如果原来文件更改,测试会失败,也就是让你确定你是不是要更改原来的文件。
例如对一个React组件而言,传入相同的props,希望得到相同的输出。这样就可以通过快照测试来完成。
按 u
可以 upadte
按 i
可以交互的更新快照
1 | expect const config = ()=>{ |
行内snapshot和普通snapshot的区别
- 普通:
toMacthSnapshot()
会把生成的快照存到一个新文件里 - 行内:
toMatchInlineSnapshot()
会把生成的快照作为toMatchInlineSnapshot()
的参数
mock timer
1 | export const timer = (callback)=>{ |
mock 类
- 使用
jest.mock(moduleName,factory,options)
自动mock模块,jest会自动帮我们mock指定模块中的函数,factory
和option
参数是可选的。factory
jest来测试ES6中的类
如果引入的文件是一个类的话,jest会默认把这个类里面的构造方法和类方法用jest.fn()代替。
1 | // 源文件 |
TDD (Test Driven Development) 测试驱动开发
- 编写测试用例
- 运行测试,测试用例无法通过测试
- 编写代码,使测试用例通过测试
- 优化代码完成开发
- 新功能则重复上述步骤
TDD优势
- 长期减少回归bug:当改变项目代码,所有测试用例会重新运行,一旦测试用例出错,就会发现原来的代码因为回归产生了bug
- 代码质量更高(在写测试的时候对代码有了比较完善的思考)
- 测试覆盖率高
BDD(Behavior Driven Development) 行为驱动开发
通过与利益相关者的讨论取得对预期的软件行为的清醒认识。它通过用自然语言书写非程序员可读的测试用例扩展了测试驱动开发方法。行为驱动开发人员使用混合了领域中统一的语言的母语语言来描述他们的代码的目的。这让开发者得以把精力集中在代码应该怎么写,而不是技术细节上,而且也最大程度的减少了将代码编写者的技术语言与商业客户、用户、利益相关者、项目管理者等的领域语言之间来回翻译的代价。
DDD(Domain Drive Design) 领域驱动开发
核心:
- 统一语言(软件的开发人员/使用人员都使用同一套语言,即对某个概念,名词的认知是统一的)
- 面向领域(以领域去思考问题,而不是模块)
DDD优势
- 使用统一的一套通用语言,沟通成本会大大减小。
- 对使用产品的用户有好处,他能在产品不断更新过程中,有一套统一流畅的体验。用户不用在每次软件更新时都要抱怨为什么之前的一个数据保存后没有用到了
- 面向领域去开发产品有助于我们深入分析产品的内在逻辑,专注于解决当前产品的核心问题,而不是冗余的做很多功能模块。
Enzyme
对ReactDOM.render进行包装
三种渲染方式
shallow
浅渲染(浅复制),仅对当前jsx结构内的顶级组件进行渲染,而不对这些组件内部嵌套的子组件进行渲染,因此行能很快mount
会进行完全渲染,而且完全依赖DOM API, 也就是说mount渲染结果跟浏览器结果一样, 结合jsdom这个工具,可以对上面提到的有内部子组件实现复杂交互功能的组件进行测试render
也会进行完整渲染,但不依赖DOM API, 而是渲染成HTML结构。
常用方法
- simulate(event,mock): 用来触发事件,但一定注意在原组件要注册这个事件
1 | const mockChange = jest.fn() |
- instance() => ReactComponent|DOMComponent :返回组件的实例。在React 16,无状态组件会返回null(即不是以class创建的组件)
- find(selector): 查找节点,参数可以是css选择器、组件内部构造函数、组件类名等
- at(index): 返回一个数组对象的第几个元素
- contains(nodeOrNodes):当前对象是否包含参数重点 node,参数类型为react对象或对象数组
- text():返回当前组件的文本内容
- html():返回当前组件的HTML代码形式
- props():返回根组件所有属性
- prop(key):返回根组件指定属性
- state():返回根组件的状态
- setState(nextState):设置根组件的状态
- setProps(nextProps):设置根组件的属性
- debug(): 会打印出测试实际渲染出的内容字符串
- first():返回节点数组的第一个元素
- last():返回节点数组的最后一个节点