隐示等待和显示等待

我们看看在功能测试中function_tests.py中的 time.sleep

inputbox.send_keys(Keys.ENTER)
time.sleep(1)
self.check_for_row_in_list_table('1: Buy peacock feathers')

这就是所谓的“显性等待”。这与“隐式等待”形成对比:在某些情况下,selenium会在认为页面正在加载时尝试“自动”等待您。

它甚至提供了一个名为隐式等待的方法,让您可以控制如果您向它请求一个似乎还不在页面上的元素,它将等待多长时间。

问题是,隐式等待总是有点不稳定,随着selenium 3的发行,隐式等待变得更加不可靠。

同时,selenium团队的普遍观点是,隐性等待只是一个坏主意,应该避免。

所以这个版本从一开始就有明确的显示等待。但问题是那些时间谁说就是正确的时间呢?对于大多数测试,我们都是针对自己的机器来定,一秒钟太长了,0.1秒就可以了。

但如果你把它定得这么低,会因为笔记本电脑有点卡那就慢一点。

因此,让我们用一个工具来代替,这个工具将等待所需的时间,直到捕捉到任何故障的很长的超时时间。

我们将把check_for_row_in_list_table重命名为wait_for_row_in_list_table,并为其添加一些轮询/重试逻辑:

from selenium.common.exceptions import WebDriverException

Max_WAIT = 10  # 1
【……】
def wait_for_row_in_list_table(self, row_text):
start_time = time.time()
while True: # 2
try:
table = self.browser.find_element_by_id('id_list_table') # 3
rows = table.find_element_by_tag_name('tr')
self.assertIn(row_text, [row_text for row in rows])
return # 4
except (AssertionError, WebDriverException) as e: # 5
if time.time() - start_time > Max_WAIT: # 6
raise e # 6
time.sleep(0.5) # 5

代码解析:

1、Max_WAIT”的常数来设置我们准备等待的最大时间。10秒应该足够捕捉任何故障或随机慢行。

2、这是一个循环,除非我们到达两条可能的出口路线之一。

3、下面是来自旧版本方法的三行断言

4、 如果我们通过了它们,断言通过了,我们就从函数返回并退出循环

5、但是,如果捕捉到异常,我们会等待很短的时间,然后循环重试。

我们要捕获两种类型的异常:页面未加载时的WebDriverException和页面上的Selenium找不到Table元素时的WebDriverException,以及表存在时的AssertionError,但它可能是页面重新加载前的表,因此它尚未包含我们的行。

6、这是我们的第二条逃生路线。如果我们达到这一点,这意味着我们的代码每次尝试都会引发异常,直到超过超时设置。所以这次,我们再次提出异常,让它冒泡到我们的测试中,并且很可能在我们的回溯中结束,告诉我们为什么测试失败。

这段代码让我们难看清到底在做什么?稍后,我们将重构一个一般的wait_for helper,以将计时和重新提升逻辑与测试断言分离。
如果您以前使用过selenium,那么您可能知道它有几个helper函数要做等待。后面我们将构建两个wait helper工具,这些工具可以生成漂亮、可读的代码。

现在我们可以重命名我们的方法调用并删除 time.sleeps:

        # 页面再次更新,清单中显示了这两个待办事项
inputbox.send_keys(Keys.ENTER)
time.sleep(1)
self.wait_for_row_in_list_table('1: Buy peacock feathers') # 页面中又显示了一个文本框,可以输入其他的待办事项
inputbox = self.browser.find_element_by_id('id_new_item')
inputbox.send_keys('Use peacock feathers to make a fly')
inputbox.send_keys(Keys.ENTER)
time.sleep(1) # 页面再次更新,她的清单中显示了这两个待办事项
self.wait_for_row_in_list_table('2: Use peacock feathers to make a fly')
self.wait_for_row_in_list_table('1: Buy peacock feathers')

python manage.py test

Ran  tests in .522s

FAILED (errors=)
Destroying test database for alias 'default'...

我们到了同一个地方,注意到执行时间也缩短了几秒钟。现在看起来可能不多,但总而言之,为了检查我们做得对,让我们用几种方法故意破坏测试,并看到一些错误。

首先,让我们检查一下,如果我们在will never appear中查找某些行文本,我们将得到正确的错误:

    def wait_for_row_in_list_table(self, row_text):
start_time = time.time()
while True: #
try:
table = self.browser.find_element_by_id('id_list_table') #
rows = table.find_element_by_tag_name('tr')
# self.assertIn(row_text, [row_text for row in rows])
self.assertIn('foo', [row_text for row in rows])
return #
except (AssertionError, WebDriverException) as e: #
if time.time() - start_time > Max_WAIT: #
raise e #
time.sleep(0.5) #

小结:

不同的测试不应该互相影响。这意味着我们需要在每次测试结束时重置任何永久状态。django的test runner通过创建一个测试数据库来帮助我们做到这一点,它在每个测试之间清除这个数据库。

每当我们需要等待加载时,time.sleep()。但问题是,我们等待的时间总是有点太长,要么太短,容易受到虚假失败的影响,这会减慢我们的测试运行速度。

不依赖selenium的隐式等待理论上selenium确实做了一些“隐式”等待,但是实现在浏览器之间是不同的,并且在编写时在selenium 3 firefox驱动程序中是非常不可靠的。“显式优于隐式”,正如python的zen所说,所以更喜欢显式等待。

Django学习系列20:改进功能测试的更多相关文章

  1. Django学习系列之Form基础

     Django学习系列之Form基础 2015-05-15 07:14:57 标签:form django 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追 ...

  2. Django学习系列6:使用selenium测试用户交互

    学习系列5中的单元测试有报错信息,这儿来编写functional_tests.py文件,扩充其中的功能测试 # File: functional_test.py # Author: Rxf # Cre ...

  3. Django学习系列12:把Python变量传入模板中渲染

    从视图的Python代码中把变量传入HTML模板. 模板中使用哪种句法引入Python对象,要使用的符号{{...}},它会以字符串的形式显示对象: <html> <head> ...

  4. Django学习系列5:为视图编写单元测试

    打开lists/tests.py编写 """向浏览器返回真正的HTML响应,添加一个新的测试方法""" from django.test i ...

  5. Django学习系列19:完成最简单可用的网站——确保功能之间相互隔离

    前面遗留的问题,首先时功能测试运行结束后的清理:其次是目前我们的待办清单只允许创建一个大家公用的清单. 如何隔离测试,运行功能测试后待办事项一直存在于数据库中,这会影响下一次测试. 运行单元测试时,D ...

  6. django学习系列——python和php对比

    python 和 php 我都是使用过,这里不想做一个非常理性的分析,只是根据自己的经验谈一下感想. 在web开发方面,无疑 php 更甚一筹. 从某种角度来说,php 就是专门为 web 定制的语言 ...

  7. Django学习系列之Python+Xadmin

    项目树 引入xadmin pycharm在项目中创建存放xadmin的目录 右键项目名称-->pythonpackage-->输入名称:extra_app 拷贝xadmin代码到extra ...

  8. Django学习系列10:保存用户输入——编写表单,发送POST请求

    要获取用户输入的待办事项,发送给服务器,这样才能使用某种方式保存待办事项,然后在显示给用户查看. 上次运行测试指出无法保存用户的输入.现在,要使用HTML post请求. 若想让浏览器发送POST请求 ...

  9. Android学习系列(20)--App数据格式之解析Json

    JSON数据格式,在Android中被广泛运用于客户端和网络(或者说服务器)通信,非常有必要系统的了解学习.     恰逢本人最近对json做了一个简单的学习,特此总结一下,以飨各位.     为了文 ...

随机推荐

  1. Django-Form组件-forms.Form

    forms.Form ​ 在之前的示例HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时很多时候都需要对用户的输入做校验,比如校验用 ...

  2. centos超详细搭建jumpserver跳板机

    一.官网 https://docs.jumpserver.org/zh/master/  二.一站式.分布式安装文档  三.选择最新版 四.在线安装文档 五.按文档部署(4G.二核.50G硬盘)  六 ...

  3. Redis的大白话解释

    Redis的官方解释可以百度,这里讲redis缓存为啥速度非常快! 这么说吧,别人问你什么是“redis”,如果你知道,你可以直接吧啦吧啦一大堆,其实这个时候你的大脑就类似redis缓存,别人问的“r ...

  4. 让样式文件,或js文件的相对路径,变成成绝对路径

    添加两行代码即可 <% String path = request.getContextPath(); String basePath = request.getScheme() + " ...

  5. SpringCloud学习(五)路由网关(zuul)(Finchley版本)

    在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现.服务消费.负载均衡.断路器.智能路由.配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统.一个简单的微服务系统如下图: ...

  6. Nginx的负载均衡和项目部署

    nginx的作用 Nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:Nginx可以作为一个HTTP服务器进行网站的发布处理,另 ...

  7. 一次JDBC支持表情存储的配置过程

    公司的一个项目,一开始没有考虑到内容字段支持表情,有一个接入方的内容含有表情要支持下 项目是基于Springboot的. 方案1先尝试直接配置数据库连接 shardingsphere: datasou ...

  8. JAVA实验报告及第七周总结

    JAVA第六周作业 实验报告五 第一题 1.设计一个类层次,定义一个抽象类--形状,其中包括有求形状的面积的抽象方法. 继承该抽象类定义三角型.矩形.圆. 分别创建一个三角形.矩形.圆存对象,将各类图 ...

  9. linux 静态库 ar命令用法

    当我们的程序中有经常使用的模块,而且这种模块在其他程序中也会用到,这时按照软件重用的思想,我们应该将它们生成库,使得以后编程可以减少开发代码量.这里介绍命令ar,用来对库操作. 1.ar基本用法 ar ...

  10. Web在线报表设计器使用指南

    市面上的报表工具有很多,虽说功能大同小异,但每一个报表工具都有各自明确的定位,选择最合适的工具,才能达到事半功倍的效果. 本文将要介绍的ActiveReports报表工具,可全面满足 .NET 报表开 ...