You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:04:57