• 0
  • 0
分享

  前言

  在我们写端到端测试之前,我们应该明确我们是基于一个用户的角度去测试我们的页面,所以这无关我们的所有源码,我们应该只专注于浏览器所呈现给我们的资源,包括页面上的element、控制台中network中的所有的请求以及导航栏上的url信息,这是我们可以去测试和观察到的所有的点。

  语法实战

  spec基本结构

// https://docs.cypress.io/api/introduction/api.html
import { DEV_SERVER } from '../config/conf'
describe('主页', () => {
  it('Home', () => {
    cy.visit('/')
    cy.contains('h1', 'QDeploy 智能安装部署平台')
    cy.get('button').click()
    cy.url().should('eq', `${DEV_SERVER}steps/selectMode`)
  })
})


  这里举一个最简单的例子,和单元测试一样,首先要把所有的用例包裹在一个describe中。在用例中先用cy.visit()方法访问地址,这里后面只加了/是因为baseUrl已经设置过了的原因。

  使用cy.contains()或者cy.get()去抓取DOM并进行断言,Cypress中默认包含的断言库为Chai。由于设有异步等待的机制,所以我们可以毫无顾及地去写下一步的操作,包括button的点击事件和跳转之后url的判断。

  生命周期

  在一个测试集合中,我们也可以加入自身的生命周期,这些生命周期主要是针对每个测试用例来执行的,包括beforeEach、beforeAll、afterEach、afterAll。我在这个测试集合中主要用到了beforeEach这个声明周期,在每个测试用例开始之前我都对我需要的DOM进行抓取并取一个别名,这样我方便其他用例需要时就不需要再反复去寻找这个节点对象了。

  beforeEach(() => {
   cy.visit('/#/steps/selectMode')
   cy.get('.one__item__right').eq(0).find('.item__right__btn').eq(0).as('hasConfigFile')
   cy.get('.one__item__right').eq(0).find('.item__right__btn').eq(1).as('notConfigFile')
   cy.get('.one__item__right').eq(1).find('.item__right__btn').eq(0).as('hasSystem')
   cy.get('.one__item__right').eq(1).find('.item__right__btn').eq(1).as('notSystem')
   cy.get('.btn__next').as('next')
   cy.get('.item__upload__text').as('fileName')
 })

  在取了别名之后其他用例只需要调用cy.get('@name')就可以取到相应别名的DOM元素。

  模拟请求

  在我们测试的时候总是会免不了一些请求的发出,在Cypress中由于是真实的浏览器环境,所以所有的请求都会被正常发出,但是有些时候我们需要mock掉一些请求来观察DOM的反馈是否符合预期,这里就需要引入一个比较重要的概念——存根stub。

  不同于单元测试的mock,我认为在单元测试中更类似于axios中的拦截器,对整个请求的代码层面进行一个拦截后返回一个相同格式的对象骗过,而在端到端测试中因为我们无法对项目本身的源码下手,所以我们只能从浏览器层面去模拟,在这里的存根我的理解是在页面发出请求之前,先对一个API做一个标记,当浏览器触发这个方法并发送请求后使用标记后的模拟请求返回并进行后续的断言操作,我们来看一下代码。

describe('installSystem', () => {
  it('寻找节点失败', () => {
    cy.server()
    cy.route({
      method: 'DELETE',
      url: 'api/find/node',
      status: 200,
      response: {
        data: {},
        error_code: 1,
        message: 'fuck'
      }
    })
    cy.visit('/#/steps/installSystem')
    cy.wait(1000)
    cy.get('.pop_content_confirm').find('div').find('div').contains('寻找节点出错')
  })
})

  在这个例子中,由于请求在页面刚被挂载后就被触发了,也就是说整个请求是写在mounted这个声明周期中的,所以我们需要在访问页面之前就对这个需要被mock的api做一个stub。

  首先我们使用cy.server()声明一个mock的请求。

  然后使用cy.route()去描述我们需要模拟的api的具体信息,在里面可以填写很多的配置,包括请求的方法method,请求的地址url,请求返回的状态码status以及最后返回的response body,在这里由于项目本身中还定义了error_code状态码,所以对于这一个请求所具备的状态我们就需要写很多个测试用例的组合去断言是否符合我们的预期。

  然后因为请求已经被我们存根了,我们再去使用cy.visit()访问一次页面就可以看到我们所需要被模拟的请求已经被存根并且成功模拟了。

1-1.png

  到目前为止我们就已经非常成功地对一个API进行模拟请求了,对比起单元测试还是方便了不少的。

  文件上传

  当然我们的网页不仅仅只有一些点击事件,我们通常还有很多特殊的操作,比如拖拽以及文件的上传等等。这里我讲解一下我遇到过的文件上传的模拟问题。

  例如我们有一个这样的场景:

1-2.png

  我图中的这个按钮中我们所使用的是input [type="file"]这个原生的输入框,所以我们无法通过value本身来获取文件并去模拟,我们需要模拟整个真实的上传操作,而显然在我们点击按钮并选择我们本地的文件是Cypress所无法做到的,毕竟不是外挂。所以我们需要自定义一条命令去完成这一步操作,这里我参考了github中Cypress官方下的一个issue,详见Adding Ability to Submit File to Input Element From Local Filesystem #170。

  7. 首先我们需要去tests -> e2e -> support -> commands.js中添加一条自定义的指令:

// 上传文件命令
Cypress.Commands.add('upload_file', (fileName, selector) => {
 cy.get(selector).then(subject => {
   cy.fixture(fileName).then((content) => {
     const el = subject[0]
     const testFile = new File([content], fileName)
     const dataTransfer = new DataTransfer()
     dataTransfer.items.add(testFile)
     el.files = dataTransfer.files
   })
 })
})

  需要声明的是我们在这个文件中我们不仅仅可以自定义指令,并且还可以更改已经存在的api,这些在文件被创建时会在开头有备注说明,这里就不展示了。

  8. 然后我们需要去tests -> e2e -> fixtures中添加我们需要上传的文件,我这里准备了一个Excel文件:

1-3.png

  最后我们来展示一下上传文件的代码段:

  it('上传文件选择有安装系统', () => {
  cy.upload_file('test.xlsx', 'input[type=file]')
  cy.get('@fileName').contains('test.xlsx')
  cy.get('@next').should('not.be.disabled')
  cy.get('@hasSystem').eq(0).click()
  cy.get('@next').click()
  cy.get('.pop_tool').find('button').eq(1).click()
  cy.url().should('eq', `${DEV_SERVER}steps/createClusters`)
})

  我们运行一下测试用例并且观看一下快照库:

1-4.png

  到这一步为止可以看到我们的文件已经上传成功了并且文件名已经被成功渲染到了页面上。


作者:钟大灵    

来源:http://www.51testing.com/html/87/n-5099587.html

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • 今天我们来聊一下测试管理者的修身齐家治国平天下。话题有点大,咋一看,这话题有点玄乎,是不是?不知道大家会不会有点懵?修身齐家治国平天下出自:《礼记·大学》原文:物格而后知至,知至而后意诚,意诚而后心正,心正而后身修,身修而后家齐,家齐而后国治,国治而后天下平。释义:修身:提高自身品德修养;齐家:整顿家庭,使家和睦;治国:治理国家;平天下:天下太平。理解:这是句激励人生、成就人生的历史名言。修身、齐家者容易,治国、平天下者难也。即便有此抱负,也未必有此机会。所以,修身先为本,"穷则独善其身、达则兼济天下"嘛,修身的办法就是物格、知至、意诚、心正,物格、知至、意诚、心正的大体意...
            0 0 1965
            分享
          • 用postman进行接口测试的时候,我们经常会把接口地址的全路径填在url地址栏当中。这种做法不太好的地方在于,当你需要从一个测试环境切换到另一测试环境时, 需要把所有的url全部修改一遍,当你有 500个用例都需要修改,直接累瘫。那在postman当中,如何更方便的修改测试环境呢?其实只需要两步。第一步,点击 postman 左侧工具栏的 environment, 点击 + 号添加新的测试环境。 一个测试环境当中可以创建很多环境变量,有了环境变量,在请求数据中就可以引用这些变量。在这里,我创建一个了一个开发环境,一个线上环境,里面都有一个叫 baseUrl 的变量。第二步,在请求发送界面,点...
            0 0 2427
            分享
          • 1、什么是接口?接口就是API,意思是应用程序编程接口。接口本质上是程序开发的函数和方法,提供参数和返回值。2、什么是接口测试?接口测试是测试系统组件间接口的一种测试,接口测试主要用于检测外部系统和内部系统之间以及各个子系统之间的交互点。测试的重点是检查数据的交换、传递和控制管理的过程,以及系统间的相互逻辑依赖关系等。3、接口组成的要素有哪些?接口访问的地址、请求的方法、参数、返回值(1)接口访问的地址 协议://IP地址或域名:端口号/应用名/功能名(2)请求的方法 get、post等(3)参数 用户使用接口时,需要向接口提供的数据。 (4)返回值 接口给用户的反馈结果。4、Pyt...
            0 2 2956
            分享
          •   数据库大量应用程序开发项目中,大多数情况下,数据库的操作性能成为整个应用的性能瓶颈。数据库的性能是程序员需要去关注的事情,当设计数据库表结构以及操作数据库(尤其是查询数据时),都需要注意数据操作的性能。本文我们以MySQL数据库为例进行讨论。  一、数据库优化目标  1、减少 IO 次数  IO永远是数据库最容易瓶颈的地方,这是由数据库的职责所决定的,大部分数据库操作中超过90%的时间都是 IO 操作所占用的,减少 IO 次数是 SQL 优化中需要第一优先考虑,当然,也是收效最明显的优化手段。  2、降低 CPU 计算  除了 IO 瓶颈之外,SQL优化中需要考虑的就是...
            8 8 1594
            分享
          • 一、测试需求:测试20个用户访问网站在负载达到30QPS时的平均响应时间二、QPS:Query Per Second 每秒查询率。(一台查询服务器每秒能够处理的查询次数,作为域名服务器的性能经常用每秒查询率来衡量)三、测试步骤1、添加线程组(线程数+准备时长+循环次数)1)线程数:虚拟用户数,一个虚拟用户占用一个进程或线程(设置多少个虚拟用户=设置多少个线程)2)准备时长(s):设置的虚拟用户数需要多长时间全部启动。eg:线程数为20,准备时长为10,则说明需要10秒钟启动20个进程。3)循环次数:每个线程发送请求的次数。eg:线程数为20,循环次数为5,那么每个线程发送5次请求,总...
            8 8 2494
            分享
      • 51testing软件测试圈微信