断言
UI自动化常见的断言条件包括:
- 通过当前页面的URL地址
- 通过当前页面的标题
- 通过当前页面的提示文本信息
- 通过当前页面的某些元素变化/显示
一句话总结:通过肉眼观察页面的变化检查。 【用代码模仿人的识别页面】
- 一般断言写一条就够了,如果业务要求比较严谨,可以写多条;
- 如果写了多条,那么每一条断言都通过 才是用例执行通过了。
登录用例的断言:
- 1、首页欢迎提示信息
- 2、首页的登录用户名显示
那么这些断言的元素定位和操作,也要封装到page_object中去。【这两个都 在home_page里】
from selenium.webdriver.common.by import By
from common.basepage_v1 import BasePage
class HomePage(BasePage):
#属性 登录链接
login_link_locator = (By.LINK_TEXT, '登录')
# 欢迎提示信息
welcome_tips_locator = (By.XPATH, '//span[text()="欢迎来到柠檬
班"]')
# 用户名
username_text_locator = (By.XPATH, '//a[@class="link-name"]')
# 操作->元素行为,登录操作
def click_login_link(self):
"""点击登录链接"""
self.wait_element_clickable(self.login_link_locator).click()
def is_dispaly_weltext(self):
"""欢迎语检查 返回文本
is_dispaly(): 元素是否存在,存在返回True 不存在返回False
"""
return self.is_display(self.welcome_tips_locator) # 直接调
用basepage里公告方法
def get_username(self):
"""获取用户名"""
return self.get_text(self.username_text_locator)
然后可以在测试用例里加上断言的代码:
- 注意: 一个用例可以添加多条断言, 测试通过的条件:所有的断言都需 要通过,有一条断言失败的,那么测试就是不通过
from page_object.login_page import LoginPage from page_object.home_page import HomePage from selenium import webdriver # pytest框架编写测试用例 def test_login(): driver = webdriver.Chrome() driver.maximize_window() driver.get("http://mall.lemonban.com:3344/") # 1、点击homepage 登录的链接 == 先实例化对象,再调用实例方法,实例 方法要传参driver HomePage(driver).click_login_link() # 2、调用LoginPage里的login实例方法 执行登录操作== 先实例化对象, 再调用实例方法,实例方法要传参 LoginPage(driver).login("lemon_py","12345678") # 断言机制检查测试是否通知(预期结果+实际结果) # 1、首页欢迎提示信息 assert HomePage(driver).is_dispaly_weltext() # 断言元素是否存在 结果True /False 可以不写。 # 2、首页的登录用户名 assert HomePage(driver).get_username() == "lemon_py"
其他的用例也可以加上同样的断言。
-
框架继续优化: 前置后置
-
这个打开浏览器获取driver 每个用例都需要, 并且每个用例执行完后,需要关闭浏览器; 我们可以定义一个夹具: 设置前置和后置操作 避免代码的重复性。
import pytest from selenium import webdriver from loguru import logger @pytest.fixture def open_browser_url(): driver = webdriver.Chrome() driver.maximize_window() driver.get('http://mall.lemonban.com:3344/') yield driver # 后置-关闭浏览器 driver.quit()
然后所有的测试用例里都可以调用这个前置,简化代码。
注意:关于所有测试用例运行期间只打开/关闭一次浏览器,不可取:
- UI自动化因为页面不太稳定,所以建议不要所有用例打开一次浏览器 关闭 一次浏览器;
- 比如中间有某个用例失败了,那么就会导致后面的用例也失败了。
- 所以每 条测试用例之间最好是独立的。 所以我们每个用例里都独立打开一次浏览器和关闭浏览器操作,可以避免很 多的问题。
basePage的是不会变化的,每个项目都可以通用的
pageobject里的是会变化的 每个项目的页面不一样,定位元素的和操作 也会不一样
testcase也会变化的,每个项目的用例不一样的。
夹具层: 基本上【除了地址】也是不变的
数据层: 变化的 每个项目要求的测试数据不一样的
日志 + 异常捕获封装: 对框架的优化
1、执行用例的过程中,没有日志 不方便定位,所以我们在一些关键的步骤里 加上日志记录。
- 在basepage和pageobject里各个方法都加上日志,记录做了什么事情
2、有些地方可能会出现错误,比如元素没有定位到,所以我们需要对这些可能 发生异常的地方加上异常捕获。在用例执行报错的时候也应有对应的报错日志 记录
思考:代码执行时候在什么地方会发生异常??
元素定位 (NoSuchElementException/TimeoutException):
- basepage里三种显示等待的方法,每个元素定位都用,元素定位 失败了,异常捕获记录日志,
- 因为元素都没有找到,就没有必要继续执行后面的代码了。-抛出 错误 代码终止运行 raise抛出
元素操作: 点击,鼠标,输入等操作虽然发生错误比较少,但是比如 有些点击失败了,也要记录日志,做异常捕获。
- 可以做异常捕获,但是因为发生错误比较少,我们也可以不做。 这里我们就简化一些。要加的 大家可以自行加上。
断言(AssertionError): 断言也可以经常会发生错误的,也肯定要做 异常捕获和日志的
- 断言成功记录日志
- 断言失败,记录日志,然后raise报错信息。
def wait_element_clickable(self, locator): logger.info(f"等待元素{locator}可以点击") try: web_element=WebDriverWait(self.driver,8,0.5).until(EC.element_to_be_clickable(locator)) except Exception as e: logger.error(f"等待元素超时{e}") raise e return web_element
元素定位和操作都加上了日志,但是断言没有加。而且断言也 没有做异常处理。
断言是一个自带的关键字,没有办法直接加日志和异常处理,如果直接在用例 里做,那么太麻烦了,每条用例都要写一遍。
- 所以要把断言的方法进行封装,封装一次,多次调用。== 封装的函数里 做异常捕获 + 日志封装
- 断言是每条用例都要用的公共方法,所以我们把它封装放在common里。
我们前面讲过,断言的常见几种方式:
- 比较相等: assert a == b
- 比较大小(大于/小于/大于等于/小于等于): assert a > b
- 内容包含/内容不包含:assert a in b
- 验证表达式是否为真: assert condition
所以这个断言封装里最好包含这些所有的情况:
- 这里单独封装了3个函数,如果后面还有其他的断言方法 可以再丰富进去。
- 在每个函数里加上日志 + 异常捕获
from loguru import logger #预期与实际进行比较 def assert_equals(actual, excepted): try: assert actual == excepted logger.info(f'断言成功,预期结果:【{excepted}】,实际结 果:【{actual}】') except Exception as e: logger.error(f'断言失败,预期结果:【{excepted}】,实际结 果:【{actual}】') raise e #str1是否在str2里面 def assert_in(str1, str2): try: assert str1 in str2 logger.info(f'断言成功,【{str1}】在【{str2}】里面的') except Exception as e: logger.error(f'断言失败,【{str1}】在【{str2}】里面的') raise e #表达式是否为真 def assert_condition(condition): try: assert condition logger.info(f'断言成功,【{condition}】为真') except Exception as e: logger.error(f'断言失败,【{condition}】为假') raise e
所有的测试用例里都可以优化替换为这个断言的封装函数。成功和失败了 就可以看到日志。