Python unittest跨类调用函数:Appium自动化UI校验需抛出错误
解决unittest中复用UI校验函数并正确抛出断言错误的问题
嘿,我来帮你搞定这个复用UI校验函数的问题!你现在遇到两个核心问题:一是原来的校验函数失败时没抛出错误,导致HTML报告没法记录失败情况;二是跨类调用方法的方式不对,直接调用类方法会导致self.driver的上下文出问题。咱们一步步来解决:
首先,重构你的UI校验函数,让它能正确抛出断言错误
原来的signin_ui_validate用了一堆嵌套if,失败时只是默默return,unittest根本不知道测试失败了。咱们换成unittest自带的断言方法,这样只要有一个元素不显示,就会直接抛出AssertionError,HTML报告会自动捕获这个错误并展示详细信息。
修改后的第一个类代码:
class Q_suite1_01(unittest.TestCase): def signin_ui_validate(self): # 每个元素检查都用self.assertTrue,附带错误提示,方便定位问题 self.assertTrue( self.driver.find_element_by_class_name('android.widget.ImageView').is_displayed(), "Quallogi Logo 未显示" ) self.assertTrue( self.driver.find_element_by_xpath('//*[contains(@text,"Sign In") and contains(@class, "android.widget.TextView")]').is_displayed(), "Sign In 标题未显示" ) self.assertTrue( self.driver.find_element_by_xpath('//*[contains(@text,"Email or Phone") and contains(@class, "android.widget.TextView")]').is_displayed(), "Email or Phone 提示文本未显示" ) self.assertTrue( self.driver.find_element_by_class_name('android.widget.EditText').is_displayed(), "手机号输入框未显示" ) self.assertTrue( self.driver.find_element_by_xpath('//*[contains(@text,"Password") and contains(@class, "android.widget.TextView")]').is_displayed(), "Password 提示文本未显示" ) self.assertTrue( self.driver.find_elements_by_class_name('android.widget.EditText')[1].is_displayed(), "密码输入框未显示" ) self.assertTrue( self.driver.find_element_by_xpath('//*[contains(@text,"Login") and contains(@class, "android.widget.TextView")]').is_displayed(), "Login 按钮未显示" ) self.assertTrue( self.driver.find_element_by_xpath('//*[contains(@text,"Forgot password?") and contains(@class, "android.widget.TextView")]').is_displayed(), "Forgot password? 链接未显示" ) self.assertTrue( self.driver.find_element_by_xpath('//*[contains(@text,"Sign up") and contains(@class, "android.widget.TextView")]').is_displayed(), "Sign up 链接未显示" ) print('Sign In UI is successfully validated')
然后,正确复用这个校验函数到第二个测试类
这里有两种靠谱的方式,你可以根据自己的测试结构选:
方式一:让第二个测试类继承第一个测试类
如果两个测试类的setup方法都是初始化同一个driver,直接继承是最方便的,这样子类可以直接调用父类的signin_ui_validate方法,上下文完全一致:
class Q_suite2_02(Q_suite1_01): # 继承Q_suite1_01 def forgotPW_rq_cancel(self): cancel_bttn = self.driver.find_element_by_xpath('//*[contains(@text,"Cancel") and contains(@class, "android.widget.TextView")]') cancel_bttn.click() # 直接调用父类的校验方法,失败会自动抛出断言错误,HTML报告能正常记录 self.signin_ui_validate()
方式二:把校验逻辑抽成独立的工具函数(更灵活)
如果不想让测试类之间有继承关系,可以把UI校验逻辑抽成一个单独的函数,接收driver作为参数,这样任何测试类只要拿到driver就能调用:
# 定义独立的工具函数,放在同一个文件或者单独的utils模块里 def validate_signin_ui(driver): assert driver.find_element_by_class_name('android.widget.ImageView').is_displayed(), "Quallogi Logo 未显示" assert driver.find_element_by_xpath('//*[contains(@text,"Sign In") and contains(@class, "android.widget.TextView")]').is_displayed(), "Sign In 标题未显示" assert driver.find_element_by_xpath('//*[contains(@text,"Email or Phone") and contains(@class, "android.widget.TextView")]').is_displayed(), "Email or Phone 提示文本未显示" assert driver.find_element_by_class_name('android.widget.EditText').is_displayed(), "手机号输入框未显示" assert driver.find_element_by_xpath('//*[contains(@text,"Password") and contains(@class, "android.widget.TextView")]').is_displayed(), "Password 提示文本未显示" assert driver.find_elements_by_class_name('android.widget.EditText')[1].is_displayed(), "密码输入框未显示" assert driver.find_element_by_xpath('//*[contains(@text,"Login") and contains(@class, "android.widget.TextView")]').is_displayed(), "Login 按钮未显示" assert driver.find_element_by_xpath('//*[contains(@text,"Forgot password?") and contains(@class, "android.widget.TextView")]').is_displayed(), "Forgot password? 链接未显示" assert driver.find_element_by_xpath('//*[contains(@text,"Sign up") and contains(@class, "android.widget.TextView")]').is_displayed(), "Sign up 链接未显示" print('Sign In UI is successfully validated') # 第一个测试类调用工具函数 class Q_suite1_01(unittest.TestCase): def signin_ui_validate(self): validate_signin_ui(self.driver) # 第二个测试类调用工具函数 class Q_suite2_02(unittest.TestCase): def forgotPW_rq_cancel(self): cancel_bttn = self.driver.find_element_by_xpath('//*[contains(@text,"Cancel") and contains(@class, "android.widget.TextView")]') cancel_bttn.click() # 传入当前类的driver调用工具函数 validate_signin_ui(self.driver)
为啥原来的代码不行?
- 原来的嵌套
if逻辑,失败时只是return,没有抛出任何异常,unittest会认为测试通过,HTML报告自然看不到错误。 - 直接调用
Q_suite1_01.signin_ui_validate()是调用未绑定的类方法,里面的self不是当前测试类的实例,要么self.driver不存在,要么不是当前正在使用的driver,肯定会出问题。
这样修改后,当UI校验失败时,会直接抛出带有详细提示的断言错误,HTML测试报告就能正确记录失败情况啦!
内容的提问来源于stack exchange,提问作者Aalia Sajana
相关产品推荐
相关产品推荐

