组件实行单元测量检验,你须求通晓的前端测量
分类:前端技术

你需要了解的前端测试“金字塔”

2017/11/24 · JavaScript · 测试

原文出处: oschina   

图片 1

如果您正在测试前端应用程序,则应该了解前端测试金字塔。

在本文中,我们将看到前端测试金字塔是什么,以及如何使用它来创建全面的测试套件。

前端测试金字塔

前端测试金字塔是一个前端测试套件应该如何构建的结构化表示。

理想的测试套件由单元测试,一些快照测试和一些端到端(e2e)测试组成。
图片 2

这是测试金字塔的改进版本,特定于测试前端应用程序。

在这篇文章中,我们将看到每个测试类型的样子。 为此,我们将为示例应用程序创建一个测试套件。

应用

要详细了解前端测试金字塔,我们来看看如何测试一个 Web 应用。

该应用是一个简单的 modal 应用。 点击一个按钮打开一个 modal ,点击 modal 上的 OK 按钮关闭 modal。

图片 3

我们将从基于组件的框架构建应用。 别担心细节,我们会保持这个(详细)的级别。

该应用由三个组件组成 – 一个 Button 组件,一个 Modal 组件和一个 App 组件。

我们要写的第一个测试是单元测试。 在前端测试金字塔中,大部分测试都是单元测试。

目前Javascript的测试工具很多,但是针对React的测试策略,Facebook推出的ReactJs标配测试工具是Jest.Jest的官网地址:。我们可以看到Jest官网宣称的是:Painless JavaScript Testing。是Facebook用于测试服务和React应用程序的JavaScript单元测试框架。

在这里说一下前端开发的一个特点是更多的会涉及用户界面,当开发规模达到一定程度时,几乎注定了其复杂度会成倍的增长。

单元测试

单元测试测试的是代码库的单元。

它们直接调用函数或单元,并确保返回正确的结果。

在我们的应用中,我们的组件是单元。所以我们将为 Button 和 Modal 编写单元测试。没有必要为我们的应用组件编写测试,因为它没有任何逻辑。

单元测试会浅渲染组件,并断言当我们与它们交互时,它们的行为是正确的。

浅渲染意味着我们渲染组件一层深度。这样我们可以确保只测试组件,单元,而不是几个级别的子组件。

在我们的测试中,我们将触发组件上的操作,并检查组件的行为是否与预期一致。

我们不用盯着代码。但是我们的组件规格会如下所示:

  • 当 displayModal 为 true 时,Modal 有类是活跃的
  • 当 displayModal 为 false 时,Modal 没有类是活跃的
  • 当成功按钮被点击时,Modal 调用 toggleModal
  • 单击删除按钮时,Modal 会调用 toggleModal
  • 当 button 被点击时,button 调用 toggleModal

我们的测试将浅渲染组件,然后检查每一项规格的工作。

单元测试应该占据我们的测试套件的绝大部分有以下几个原因:

所谓单元测试也就是对每个单元进行测试,通俗的将一般针对的是函数,类或单个组件,不涉及系统和集成。单元测试是软件测试的基础测试。Jest主要有以下特点:

无论是在代码的初始搭建过程中,还是之后难以避免的重构和修正bug过程中,常常会陷入逻辑难以梳理、无法掌握全局关联的境地。

单元测试很快

几百个单元测试套件能在几秒钟内运行。

这使得单元测试对开发很有用。 当重构代码时,我们可以更改代码,并在没有中断组件的情况下运行单元测试来检查更改。 我们会在几秒钟之内知道我们是否破坏了代码,因为其中一个测试会失败。

  1. 适应性:Jest是模块化、可扩展和可配置的。
  2. 沙箱和快速:Jest虚拟化了JavaScript的环境,能模拟浏览器,并且并行执行
  3. 快照测试:Jest能够对React 树进行快照或别的序列化数值快速编写测试,提供快速更新的用户体验。
  4. 支持异步代码测试:支持promises和async/await
  5. 自动生成静态分析结果:不仅显示测试用例执行结果,也显示语句、分支、函数等覆盖率。

图片 4

单元测试是细颗粒的。

换句话说,他们是非常具体的。

如果一个单元测试失败了,那么这个测试会告诉我们它是如何以及为什么失败的。

单元测试能很好地检查我们的应用程序工作的细节。 它们是开发时最好的工具,特别是如果你遵循测试驱动的开发。

但是它们无法测试一切。

为了确保我们呈现正确的样式,我们还需要使用快照测试。

为什么要使用单元测试工具

而单元测试作为一种“提纲挈领、保驾护航”的基础手段,为开发提供了“围墙和脚手架”,可以有效的改善这些问题。

快照测试

快照测试是测试你的渲染组件的图片,并将其与组件的以前的图片进行比较。

用 JavaScript 编写快照测试的最好方法是使用 Jest 。

Jest 不是拍摄渲染组件的图片,而是渲染组件标记的快照。 这使得 Jest 快照测试比传统快照测试快得多。

要在 Jest 中注册快照测试,需要添加如下代码:

const renderedMarkup = renderToString(ModalComponent) expect(renderedMarkup).toMatchSnapshot()

1
2
const renderedMarkup = renderToString(ModalComponent)
expect(renderedMarkup).toMatchSnapshot()

一旦你注册一个快照,Jest 将顾及其它的一切。 每次运行单元测试时,都会重新生成一个快照,并将其与之前的快照进行比较。

如果代码改变,Jest 会抛出一个错误,并警告标记已经改变。 然后开发者可以手动检查没有类被误删的情况。

在下面的测试中,有人从<footer>中删除了 modal-card-foot 类。

图片 5

快照测试是一种检查组件样式或标记的方法。

如果快照测试通过,我们知道代码更改不会影响组件的显示。

如果测试失败,那么我们知道确实影响了组件的渲染,并可以手动检查样式是否正确。

每个组件至少应有一次快照测试。 一个典型的快照测试呈现组件的状态,以检查它正确呈现。

现在我们已经有了单元测试和快照测试,是时候看看端到端(e2e)测试。

我们在开发过程中,不使用测试工具依然可以自己写代码进行单元测试,但是我们的代码存在着相互调用关系,在测试过程中我们又希望使单元相对独立而又能正常运行,就需要我们对被测函数的依赖函数和环境进行mock,并且在测试数据输入、测试执行和测试结果检查方面存在很多相似性,测试工具正是为我们在这些方面提供了方便。

作为一种经典的开发和重构手段,单元测试在软件开发领域被广泛认可和采用;前端领域也逐渐积累起了丰富的测试框架和最佳实践。

端到端测试

端到端(e2e)测试是高层测试。

它们执行与我们手动测试应用程序时相同的操作。

在我们的应用程序中,我们有一个用户(操作)旅程。当用户点击按钮时,模式将打开,当他们点击模式中的按钮时,模式将关闭。

我们可以编写一个贯穿这一旅程的端到端测试。测试将打开浏览器,导航到网页,并通过每个操作来确保应用程序正常运行。

这些测试将告诉我们,我们的单元正确地协同工作。它使我们高度自信,该应用程序的主要功能是可以正常工作的。

对 JavaScript 应用程序来说有几种方法可以编写端到端测试。像 test cafe 这样的程序会记录您在浏览器中执行操作并将其作为测试源重播。

还有类似 nightwatch 的项目,可让你用 JavaScript 编写测试项目。我会推荐使用类似 nightwatch 的库。拿起来直接用很容易,该测试运行速度比记录的测试更快。

也就是说,night1qtch 的测试还是比较慢的。一套200个单元测试需要花费几分钟的时间,一套200个端到端测试仅需要几分钟时间来运行。

端到端测试的另一个问题是难以调试。当测试失败时,很难找出失败的原因,因为测试涵盖了太多功能。

准备阶段

图片 6

结语

要有效地测试基于前端组件的 Web 应用程序,你需要三种类型的测试:单元测试,快照测试和 e2e 测试。

你应该对每个组件进行多个单元测试,对每个组件进行一次或两次快照测试,以及测试链接在一起的多个组件的一次或两次端到端测试。

整体单元测试将涵盖大部分测试,你将有一些快照测试和一些 e2e 测试。

如果你遵循前端测试金字塔,你就可以使用杀手级测试套件创建可维护的 Web 应用程序。

你可以在 GitHub 上看到应用程序的快照测试、单元测试和端到端测试的示例源码库。

1 赞 收藏 评论

图片 7

需要一个rn项目,这里演示的是我个人的项目ReactNative-ReduxSaga-TODO

本文将按如下顺序进行说明:

安装jest

  • I. 单元测试简介
  • II. React 单元测试中用到的工具
  • III. 用测试驱动 React 组件重构
  • IV. React 单元测试常见案例

如果你是用react-native init命令行创建的rn项目,并且你的rn版本在0.38以上,则无需安装了。不太清楚的话就看一下

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。

package.json文件中是否包含以下代码:

简单来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

 // package.json
 "scripts": {
  "test": "jest"
 },
 "jest": {
  "preset": "react-native"
 }

测试框架

测试框架的作用是提供一些方便的语法来描述测试用例,以及对用例进行分组。

如果没有就安装一下npm i jest --save-dev,并把上述代码添加到package.json文件的对应位置。

断言(assertions)

断言是单元测试框架中核心的部分,断言失败会导致测试不通过,或报告错误信息。

对于常见的断言,举一些例子如下:

  • 同等性断言 Equality Asserts

    • expect.toEqual
    • expect.not.toEqual
  • 比较性断言 Comparison Asserts

    • expect.toBeGreaterThan
    • expect.toBeLessThanOrEqual
  • 类型性断言 Type Asserts

    • expect.toBeInstanceOf
  • 条件性测试 Condition Test

    • expect.toBeTruthy()
    • expect.toBeFalsy()
    • expect.toBeDefined()

以上步骤完成后,简单运行npm run test测试一下jest是否配置成功。但我们没有写测试用例,终端会打印no tests found。这时就配置完成了。

断言库

断言库主要提供上述断言的语义化方法,用于对参与测试的值做各种各样的判断。这些语义化方法会返回测试的结果,要么成功、要么失败。常见的断言库有 Should.js, Chai.js 等。

快照测试

测试用例 test case

为某个特殊目标而编制的一组测试输入、执行条件以及预期结果,以便测试某个程序路径或核实是否满足某个特定需求。

一般的形式为:

it('should ...', function() { ... expect.toEqual;

写一个组件

测试套件 test suite

通常把一组相关的测试称为一个测试套件

一般的形式为:

describe('test ...', function() { it('should ...', function() { ... }); it('should ...', function() { ... }); ...});
import React from 'react';
import {
 Text, View,
} from 'react-native';

import PropTypes from 'prop-types';

const PostArea = ({ title, text, color }) => (
 <View style={{ backgroundColor: '#ddd', height: 100 }}>
  <Text style={{ fontSize: 30 }}>{title}</Text>
  <Text style={{ fontSize: 15, color }}>{text}</Text>
 </View>
);

export default PostArea;

spy

正如 spy 字面的意思一样,我们用这种“间谍”来“监视”函数的调用情况

通过对监视的函数进行包装,可以通过它清楚的知道该函数被调用过几次、传入什么参数、返回什么结果,甚至是抛出的异常情况。

var spy = sinon.spy(MyComp.prototype, 'componentDidMount');...expect(spy.callCount).toEqual;

在项目根目录下找到__test__文件夹,现在,让我们使用React的测试渲染器和Jest的快照功能来与组件进行交互,并捕获呈现的输出并创建一个快照文件。

stub

有时候会使用stub来嵌入或者直接替换掉一些代码,来达到隔离的目的

一个stub可以使用最少的依赖方法来模拟该单元测试。比如一个方法可能依赖另一个方法的执行,而后者对我们来说是透明的。好的做法是使用stub 对它进行隔离替换。这样就实现了更准确的单元测试。

var myObj = { prop: function() { return 'foo'; }};sinon.stub(myObj, 'prop').callsFake(function() { return 'bar';});myObj.prop(); // 'bar'
// PostArea_test.js
import 'react-native';
import React from 'react';
import PostArea from '../js/Twitter/PostArea';

import renderer from 'react-test-renderer';

test('renders correctly', () => {
 const tree = renderer.create(<PostArea title="title" text="text" color="red" />).toJSON();
 expect(tree).toMatchSnapshot();
});

mock

mock一般指在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法

广义的讲,以上的 spy 和 stub 等,以及一些对模块的模拟,对 ajax 返回值的模拟、对 timer 的模拟,都叫做 mock 。

然后在终端运行npm run test或jest。将会输出:

测试覆盖率(code coverage)

用于统计测试用例对代码的测试情况,生成相应的报表,比如 istanbul 是常见的测试覆盖率统计工具

PASS  __tests__PostArea_test.js (6.657s)
  √ renders correctly (5553ms)

 › 1 snapshot written.
Snapshot Summary
 › 1 snapshot written in 1 test suite.

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   1 added, 1 total
Time:        8.198s
Ran all test suites.

Jest

图片 8

不同于"传统的"的 jasmine / Mocha / Chai 等前端测试框架 -- Jest的使用更简单,并且提供了更高的集成度、更丰富的功能。

Jest 是 Facebook 出品的一个测试框架,相对其他测试框架,其一大特点就是就是内置了常用的测试工具,比如自带断言、测试覆盖率工具,实现了开箱即用。

此外, Jest 的测试用例是并行执行的,而且只执行发生改变的文件所对应的测试,提升了测试速度。

编写单元测试的语法通常非常简单;对于jest来说,由于其内部使用了 Jasmine 2 来进行测试,故其用例语法与 Jasmine 相同。

实际上,只要先记这住四个单词,就足以应付大多数测试情况了:

  • describe: 定义一个测试套件
  • it:定义一个测试用例
  • expect:断言的判断条件
  • toEqual:断言的比较结果
describe('test ...', function() { it('should ...', function() { expect.toEqual; expect(sth.length).toEqual; expect(sth > oth).toEqual;});

Jest 号称自己是一个 “Zero configuration testing platform”,只需在 npm scripts里面配置了test: jest,即可运行npm test,自动识别并测试符合其规则的(一般是 __test__ 目录下的)用例文件。

实际使用中,适当的自定义配置一下,会得到更适合我们的测试场景:

//jest.config.jsmodule.exports = { modulePaths: [ "<rootDir>/src/" ], moduleNameMapper: { ".$": '<rootDir>/__test__/NullModule.js' }, collectCoverage: true, coverageDirectory: "<rootDir>/src/", coveragePathIgnorePatterns: [ "<rootDir>/__test__/" ], coverageReporters: ["text"],};

在这个简单的配置文件中,我们指定了测试的“根目录”,配置了覆盖率(内置的istanbul)的一些格式,并将原本在webpack中对样式文件的引用指向了一个空模块,从而跳过了这一对测试无伤大雅的环节

//NullModule.jsmodule.exports = {};

另外值得一提的是,由于jest.config.js是一个会在npm脚本中被调用的普通 JS 文件,而非XXX.json.XXXrc的形式,所以 nodejs 的各自操作都可以进行,比如引入 fs 进行预处理读写等,灵活性非常高,可以很好的兼容各种项目

由于是面向src目录下测试其React代码,并且还使用了ES6语法,所以项目下需要存在一个.babelrc文件:

{ "presets": ["env", "react"]}

以上是基本的配置,而实际由于webpack可以编译es6的模块,一般将babel中设为{ "modules": false },此时的配置为:

//package.json"scripts": { "test": "cross-env NODE_ENV=test jest",},

//.babelrc{ "presets": [ ["es2015", {"modules": false}], "stage-1", "react" ], "plugins": [ "transform-decorators-legacy", 如果对软件测试、接口测试、自动化测试、性能测试、LR脚本开发、面试经验交流。 "react-hot-loader/babel" 感兴趣可以175317069,群内会有不定期的发放免费的资料链接,这些资料都是从各 ], 个技术网站搜集、整理出来的,如果你有好的学习资料可以私聊发我,我会注明出处 "env": { 之后分享给大家。 "test": { "presets": [ "es2015", "stage-1", "react" ], "plugins": [ "transform-decorators-legacy", "react-hot-loader/babel" ] } }}

同时,在test文件夹下会输出一个文件,即为生成的快照。

Enzyme

Enzyme 来自于活跃在 JavaScript 开源社区的 Airbnb 公司,是对官方测试工具库(react-addons-test-utils)的封装。

这个单词的伦敦读音为 ['enzaɪm],酵素或酶的意思,Airbnb 并没有给它设计一个图标,估计就是想取用它来分解 React 组件的意思吧。

它模拟了 jQuery 的 API,非常直观并且易于使用和学习,提供了一些与众不同的接口和几个方法来减少测试的样板代码,方便判断、操纵和遍历 React Components 的输出,并且减少了测试代码和实现代码之间的耦合。

一般使用 Enzyme 中的 mountshallow 方法,将目标组件转化为一个 ReactWrapper对象,并在测试中调用其各种方法:

import Enzyme,{ mount } from 'enzyme';...describe('test ...', function() { it('should ...', function() { wrapper = mount( <MyComp isDisabled={true} /> ); expect( wrapper.find.exists.toBeTruthy;
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders correctly 1`] = `
<View
 style={
  Object {
   "backgroundColor": "#ddd",
   "height": 100,
  }
 }
>
 <Text
  accessible={true}
  allowFontScaling={true}
  disabled={false}
  ellipsizeMode="tail"
  style={
   Object {
    "fontSize": 30,
   }
  }
 >
  title
 </Text>
 <Text
  accessible={true}
  allowFontScaling={true}
  disabled={false}
  ellipsizeMode="tail"
  style={
   Object {
    "color": "red",
    "fontSize": 15,
   }
  }
 >
  text
 </Text>
</View>
`;

sinon

图片 9

图中这位“我牵着马”的并不是卷帘大将沙悟净...其实图中的故事正是人所皆知的“特洛伊木马”;大概意思就是希腊人围困了特洛伊人十多年,久攻不下,心生一计,把营盘都撤了,只留下一个巨大的木马,以及这位被扒光还被打得够呛的人,也就是此处要谈的主角sinon,由他欺骗特洛伊人 --- 后面的剧情大家就都熟悉了。

所以这个命名的测试工具呢,也正是各种伪装渗透方法的合集,为单元测试提供了独立而丰富的 spy, stub 和 mock 方法,兼容各种测试框架。

虽然 Jest 本身也有一些实现 spy 等的手段,但 sinon 使用起来更加方便。

修改源文件

这里不展开讨论经典的 “测试驱动开发”(TDD - test driven development) 理论

简单的说,把测试正向加诸开发,先写用例再逐步实现,就是TDD,这是很好理解的。

而当我们反过头来,对既有代码补充测试用例,使其测试覆盖率不断提高,并在此过程中改善原有设计,修复潜在问题,同时又保证原有接口不收影响,这种 TDD 行为虽然没人称之为“测试驱动重构”(test driven refactoring),但“重构”这个概念本身就包含了用测试保驾护航的意思,是必不可少的题中之意。

对于一些组件和共有函数等,完善的测试也是一种最好的使用说明书。

在下一次运行测试的时候,呈现的输出将与之前创建的快照进行比较。快照应该和代码一起提交。当快照测试失败的时候,就需要检查是否有意或无意的更改。如果是和预期中的变化一样,调用jest -u来覆盖当前的快照。

失败-编码-通过 三部曲

由于测试结果中,成功的用例会用绿色表示,而失败的部分会显示为红色,所以单元测试也常常被称为 “Red/Green Testing” 或 “Red/Green Refactoring” , 这也是 TDD 中的一般性步骤:

  1. 添加一个测试
  2. 运行所有测试,看看新加的这个是不是失败了;如果能成功则重复步骤1
  3. 根据失败报错,有针对性的编写或改写代码;这一步的唯一目的就是通过测试,先不必纠结细节
  4. 再次运行测试;如果能成功则跳到步骤5,否则重复步骤3
  5. 重构已经通过测试的代码,使其更可读、更易维护,且不影响通过测试
  6. 重复步骤1

图片 10图片 11

如果对软件测试、接口测试、自动化测试、性能测试、LR脚本开发、面试经验交流。感兴趣可以175317069,群内会有不定期的发放免费的资料链接,这些资料都是从各个技术网站搜集、整理出来的,如果你有好的学习资料可以私聊发我,我会注明出处之后分享给大家。

我们来更改一下原来的代码:把第二行<Text>的字号改为14.

解读测试覆盖率

图片 12

这就是 jest 内置的 istanbul 输出的覆盖率结果。

之所以叫做“伊斯坦布尔”,是因为土耳其地毯世界闻名,而地毯是用来"覆盖"的

本文由pc28.am发布于前端技术,转载请注明出处:组件实行单元测量检验,你须求通晓的前端测量

上一篇:15个有用和强大的CSS工具推荐,8个非常有用的C 下一篇:没有了
猜你喜欢
热门排行
精彩图文