Cypress同TestCafe一样,也是被誉为UI自动化测试后Selenium时代的三驾马车之一,从GitHub的star数量来说,Cypress远超TestCafe,可见其受欢迎程度。笔者项目中也是使用的Cypress,确实很好用,所以想要推荐给大家。
Cypress主要有以下特点:
1.Cypress记录了测试用例运行snapshots,可以查看用例运行轨迹,易于Debug
2.内置自动等待,不需要手动加wait或者sleep
3.交互式的TestRunner界面,测试情况一目了然
4.可以模拟网络请求流量
5.dashboard可以完美展示CI运行情况
之后的系列文章会一一介绍这些特点,今天这篇会介绍如何安装Cypress,然后使用Cypress运行第一个测试用例。
1.在任意目录下新建一个空文件夹,然后执行:npm init 初始化一个项目
2.使用IntelliJ打开项目,在命令行执行:npm install cypress --save-dev
3.打开cypress:node_modules/.bin/cypress open
首次打开的cypress会自动加载一些example,如下图
我们也可以将打开cypress的命令写在package.json文件中,以后打开cypress直接运行:npm run cypress:open即可
"scripts": {
"cypress:open": "node_modules/.bin/cypress open"
}
点击运行第一个测试用例actions.spec.js,这是cypress会启动Chrome浏览器运行该测试用例,并且可以在TestRunner的左边看到运行了哪些测试用例,哪些成功了,哪些失败了,一目了然。
然后我们回到我们的项目源码中,可以看到新增了一些文件和目录,新增了cypress目录并在其下有四个文件夹,新增了cypress.json文件。这是刚刚我们运行cypress引入的cypress给的demo,它也就帮我们生成好了标准的目录结构。目录结构如下图所示:
下面我们就来介绍一下使用cypress进行UI测试的项目源码目录结构。
1.fixtures:存放测试用例需要使用的测试数据。
2.integration:存放测试用例,我们可以看到文件夹下的所有js文件均以spec结尾,这也是cypress的内在设置,它只会将以spec的文件识别为测试用例,当然不一定是js文件,它也支持.jsx/.coffee/.cjsx文件。
3.plugins:加载插件的文件,cypress支持很多插件,可在其官网查看,下文也将介绍几个常用插件。
4.support:里面的command.js文件用于自定义命令,index.js文件可以用于配置一些通用配置,每个测试用例运行前会先运行该文件。
5.cypress.json:cypress默认的全局配置文件,比如配置生成报告的路径、访问的baseUrl、用例运行超时时间等等。具体的配置可参照官网:https://docs.cypress.io/guides/references/configuration.html#Options,下文也将介绍一些常见配置。
我们可以打开其中的一个用例actions.spec.js查看一下用例结构,一个js文件有多个context/describe,一个describe包含了多个it描述的测试用例,所以可以将一个describe包含的内容当作一个测试集,其中包含多个测试用例。
下面我们就用cypress开始写我们的第一个测试用例:微博首页搜索,然后注册账号。
如果你之前从未写过UI测试,甚至不知道怎么开头,那么我们就可以按以下步骤进行:
1.Visit a web page.
2.Query for an element.
3.Interact with that element.
4.Assert about the content on the page
用例代码如下
weiboSignUpTest.spec.js
describe('weibo sign up test', () => {
beforeEach('visit sign up page of weibo', () => {
cy.visit('https://weibo.com/signup/signup.php')
})
it('should sign up in weibo successfully', () => {
cy.get('input[name=username]').type('123')
cy.get('input[name=passwd]').type('123098')
cy.get('select[node-type=birthday_year]').select('1995')
cy.get('select[node-type=birthday_month]').select('2')
cy.get('select[node-type=birthday_day]').select('21')
cy.get('input[name=pincode]').type('123')
cy.get('a[action-type=btn_submit]').click()
cy.get('.error').should('contain', '手机号长度11位,以13/14/15/16/17/18/19开头')
})
})
我们使用pageObject的思想重构测试用例:
weiboSignUpPage.js
function inputUserName(userName) {
cy.get('input[name=username]').type(userName)
}
function inputPassword(password) {
cy.get('input[name=passwd]').type(password)
}
function selectBirthday(year, month, day) {
cy.get('select[node-type=birthday_year]').select(year)
cy.get('select[node-type=birthday_month]').select(month)
cy.get('select[node-type=birthday_day]').select(day)
}
function inputPinCode(pinCode) {
cy.get('input[name=pincode]').type(pinCode)
}
function submit() {
cy.get('a[action-type=btn_submit]').click()
}
function shouldShowErrorMessage(errorMessage) {
cy.get('.error').should('contain', errorMessage)
}
module.exports = {
inputUserName: inputUserName,
inputPassword: inputPassword,
inputPinCode: inputPinCode,
selectBirthday: selectBirthday,
submit: submit,
shouldShowErrorMessage: shouldShowErrorMessage
}
weiboSignUpTest.spec.js
import signUpPage from './weiboSignUpPage'
describe('weibo sign up test', () => {
beforeEach('visit sign up page of weibo', () => {
cy.visit('https://weibo.com/signup/signup.php')
})
it('should sign up in weibo successfully', () => {
signUpPage.inputUserName('123')
signUpPage.inputPassword('123098')
signUpPage.selectBirthday('1995', '2', '21')
signUpPage.inputPinCode('123')
signUpPage.submit()
signUpPage.shouldShowErrorMessage('手机号长度11位,以13/14/15/16/17/18/19开头')
})
})
由此可见,只要了解一些cypress的常用api,写测试用例是十分简单的。