iTesting软件测试知识分享

你不知道的Cypress系列(5) -- 眼瞎的TestRunner​

今天是<你不知道的Cypress系列>的第五篇 – 眼瞎的TestRunner​(买了书的同学们,公众号回复你的微信,拉你到Cypress中国群)。

自从我的新书 前端自动化测试框架 – Cypress从入门到精通上市以来,这本书受到了大量同学热情的追捧和讨论。在跟同学们的交流中,我也了解到, 原来除了国外优秀的公司(例如Adobe, 迪士尼,AutoDesk等等), 国内也有很多公司在尝试使用Cypress提升测试效率。而在Cypress中国群内、在公众号iTesting里,我每天都能看到大量关于Cypress的使用讨论和私下问询。这让我感到无比荣幸。

(一)PageObject是什么

关于TestRunner, 我想大家都已经非常熟悉了。在我的的书中也有其各个用法的专门介绍,这里不再赘述。

仅再次列下其定义:

1
2
3
4
5
//关注微信公众号iTesting,与万人测试团体共同成长。
TestRunner是一个独特的测试运行器。Cypress的所有命令通过它运行。
通过TestRunner你可以观测到, 在某一个时刻:
1. 哪些命令在执行。
2. 这些命令在执行时,你的应用程序处于什么状态。

Cypress八大特性里的时间穿梭能力,和可调试性能力,其实就是通过TestRunner来实现的。

(二)Test Runner两种运行模式

Cypress有两种运行方式,分别是交互性运行(Interaction Mode),和无头(Headless Mode)运行。

区别一个是测试运行时你可以看到浏览器启动、执行测试。另一个是没有浏览器界面,你看不到运行过程。

无论是哪种方式运行,大家记得Cypress 是通过它内置的Test Runner来运行你的测试用例的就行。

(三)什么, TestRunner也会“瞎”?!

没想到吧?刚开始我也是拒绝相信的。直到我发现我的测试用例还是会出现不稳定、随机失败的现象(Flaky Test)。怪了!不是说用了Cypress之后就不会有这种问题了么?于是我就寻仙访药啊,终于,找到了原因所在。先给大家看一个例子:

1
2
3
4
5
6
7
8
describe('iTesting Demo', () => {
it('欢迎关注iTesting', () => {
cy.visit('/?delay=500')
cy.get('.loading').should('be.visible')
cy.get('.loading').should('not.be.visible')
cy.get('li.todo').should('have.length', 2)
})
})

这是Cypress官网的一个用例,这个测试第一次成功,再次运行失败了。特别是你把它集成到CI上的时候,你大概率会看到这种失败。

为什么会这样呢?
Test Runner “瞎”了!

(四)TestRunner为什么会“瞎”

我们知道,修复一个Bug的最好手段就是稳定重现它。怎么重现呢? 先设定一个小目标,先运行它个20次试试:

1
2
3
4
5
6
7
8
9
10
11
describe('iTesting Demo', () => {
Cypress._.times(20, (k) => {
it(`欢迎关注iTesting ${k}`, () => {
cy.visit('/?delay=500')
cy.get('.loading').should('be.visible')
cy.get('.loading').should('not.be.visible')
cy.get('li.todo').should('have.length', 2)
})
})
})
多次运行能够暴露出代码中的潜在问题,我建议所有要上CI运行的测试用例在提交到代码仓库时,都这样多次运行下!

这世界上啊,什么事都怕你有目的。果然目标一定,出现错误的次数就增加到过5次了。

那么我们确定,代码是有问题,再一眼一眼看吧。这个时候,有条件的你可能也要看下开发的代码如何写的。例如,visit的时候发生了什么, click的时候哪些事件被触发了? 通过了解开发逻辑可以帮助你快速定位问题。

经过一番调查啊,猜测出问题的代码在第4行和第5行。当元素(类名”.loading“)加载速度过快时候,就大概率会引发失败。

来初步验证下:

1
2
3
4
5
6
7
8
9
10
describe('iTesting Demo', () => {
it('欢迎关注iTesting', () => {
cy.visit('/?delay=500')
cy.get('.loading').should('be.visible')
cy.wait(1000)
cy.get('.loading').should('not.be.visible')
cy.get('li.todo').should('have.length', 2)
})
})

哎,加了等待就不会出这个bug了。说明问题就在这里了:

也就是说,元素已经完成show的操作并且马上变成disappear了,但Cypress的Test Runner还没反应过来,还在检查元素show出来没。

(五)结论

然后就是各种查资料, 最后发现Cypress早有结论:

1
1. 如果一个元素出现和消失的间隔在21ms内,那么大概率TestRunner会“瞎”。

有的同学可能会想, Test Runner看不见,有没有其它办法能看见?比如Cypress不是提供视频可以录制运行中的所有情况么?我把运行过程录制下来慢慢查不就行了?

1
1. 不行!标准的视频,是每秒30帧, 每帧的标准间隔是33ms。

(六)解决之道

既然找到了Root cause,解决起来就简单了,有如下解法:

  1. 加Sleep time

    1
    2
    // 强烈不推荐, 用了我大Cypress,是不可能sleep的!
    cy.wait(1000)
  2. 使用cy.intercept等待网络请求返回并加装完成后再执行

    1
    2
    3
    4
    // 强烈推荐!
    cy.intercept('XXX你的代码').as('myRequest')
    cy.wait('@myRequest')
    xxxxx // 你的后续代码
  3. 直接模拟服务器延迟返回

    1
    2
    3
    4
    5
    //五星好评,强烈推荐!
    cy.intercept('/todos', {
    fixture: 'todos.json',
    delayMs: 1000,
    })

Cypress有很多奇淫巧技, 我已经总结超过百篇,别走开,下一篇更精彩!

往期回看:
你不知道的Cypress系列(1) –鸡肋的BDD

你不知道的Cypress系列(2) –该死的PO模型​

你不知道的Cypress系列(3) – 是时候重构你的思维了

你不知道的Cypress系列(4) – “PO”已死,App Action当立

🐶 您的支持将鼓励我继续创作 🐶
-------------评论, 吐槽, 学习交流,请关注微信公众号 iTesting-------------
请关注微信公众号 iTesting wechat
扫码关注,跟作者互动

本文标题:你不知道的Cypress系列(5) -- 眼瞎的TestRunner​

文章作者:请关注微信公众号 iTesting

发布时间:2021年03月19日 - 22:03

最后更新:2021年12月10日 - 23:12

原始链接:http://www.helloqa.com/2021/03/19/你不知道的Cypress系列/你不知道的Cypress系列5眼瞎的TestRunner​/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。