栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

使用selenium + pytest + allure做WBE UI自动化

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用selenium + pytest + allure做WBE UI自动化

目录结构

依然使用了常见的po 模式

  • 目录结构
    • config
      • config.ini 修改目标路由与相关配置
    • elements
      • 抽象页面空间元素
    • method
      • 抽象页面方法
    • TestCase
      • 测试用例
    • utils
      • Assert 自定义断言
      • chromedriver 浏览器驱动 需匹配版本 非linux 环境无视
      • Driver 初始化driver
      • graphical 图片相对定位
      • log 日志
      • seleniumBase api封装
      • seleniumOpt opt定义
初始化Driver

根据判断运行环境 选择不同的chrome driver 或者使用 ChromeDriverManager 自动下载

class Driver:

    @classmethod
    def driver(cls):
        try:
            # select local or docker
            # if platform == "Darwin":
            # url = Config().get_conf("dockerHub", "url")
            # driver = webdriver.Remote(url, desired_capabilities=capabilities(),
            #                           options=options())
            # # else:
            if platform.system() == "Linux":
                executable_path = os.path.join(os.path.dirname(__file__), "chromedriver")
                driver = webdriver.Chrome(executable_path=executable_path, options=options())
            else:
                executable_path = ChromeDriverManager().install()
                driver = webdriver.Chrome(executable_path=executable_path, options=options())
            driver.implicitly_wait(20)
            log.info(f"driver:{driver.name}")
            return driver
        except BaseException as e:
            log.error(e)
            raise e

自定义driver 的options 配置

def options():
    """
    浏览器设置
    :return:
    """
    _options = ChromeOptions()
    # # 设置chrome为手机界面
    # mobileEmulation = Config().get_conf("seleniumOpt", "mobileEmulation")
    # if mobileEmulation == 'true':
    #     mobile_emulation = {"deviceName": "Galaxy S5"}
    #     _options.add_experimental_option("mobileEmulation", mobile_emulation)
    if platform.system() == 'Darwin':
        pass
    else:
        _options.add_argument('--headless')
        _options.add_argument('--no-sandbox')
        _options.add_argument('--disable-gpu')
        _options.add_argument('--disable-dev-shm-usage')

    return _options

Base类

封装常用API 把driver 实例化传入
查找元素尽量使用显示等待 expected_conditions
使用了Faker 可随意生成测试数据
查找元素失败 使用allure 上传截图

class SeleniumBaseConfig:
    faker = Faker(locale="zh_CN")
    Assert = Assert
    log = get_log()

    def __init__(self, driver: webdriver):
        """
        :param driver: 驱动
        """
        self.driver = driver

    def find_element(self, locator: tuple, timeout=5):
        """
        find_element
        :param locator: (xpath,xxx)(id,xxx)
        :param timeout: timeout
        :return:
        """
        try:
            element = WebDriverWait(self.driver, timeout).until(EC.presence_of_element_located(locator))
            self.log.info(f"[{self.find_element.__name__}]  locator: {locator} element: {str(element)}")
            return element
        except WebDriverException as e:
            self.log.error(e)
            allure.attach(self.get_png(), "异常截图", allure.attachment_type.PNG)
            allure.attach("未找到: {}, 详细信息如下: {}".format(locator, e))
            raise e

自定Assert

很常规 没什么可说的

class Assert:

    @staticmethod
    def assert_unequal(exp, res):
        try:
            log.info("ASSERT UNEQUAL: EXPECT IS [{}] RESULT IS [{}]".format(exp, res))
            assert exp != res
            return True
        except AssertionError as e:
            log.error("ASSERT UNEQUAL ERROR: EXPECT IS [{}] RESULT IS [{}]".format(exp, res))
            raise e

关于页面元素

根据op 依旧对页面抽象成类 并继承SeleniumBaseConfig
元素类1一对1配套

class RegisterMethod(SeleniumBaseConfig):


    def __init__(self, driver):
        super().__init__(driver)

    def register(self, mobile: str):
        """
        注册
        :param mobile
        :return:
        """
        self.send_keys(RegisterLogin.INPUT_NUMBER, mobile)
        self.click(RegisterLogin.NEXT_STEP_BUTTON)
        time.sleep(1)

对应元素类

class Register:
    # ================== 公共 ================
    # 下一步
    NEXT_STEP_BUTTON = ("xpath", "//button")
    # 返回
    RETURN = ('xpath', '//p[@]')
    # input 错误信息
    INPUT_ERROR_INFO = ("xpath", '//p[@]')

    # ================== home界面 ================
    CREATE_BUTTON = ("xpath", "//div[text()='创建']")  # 创建button
    JOIN_BUTTON = ("xpath", "//div[text()='加入']")  # 创建button

    INPUT_TEAM_NAME = ("xpath", '//input[@placeholder="请输入团队名称"]')  # 输入团队名称
    INPUT_YOUR_NAME = ("xpath", '//input[@placeholder="请输入你的姓名"]')  # 输入个人名称

测试用例
	@pytest.mark.P3
    @allure.title("创建新团队:姓名输入汉字、英文、数字字符")
    @pytest.mark.flaky(reruns=1, reruns_delay=2)
    def test_create_team_username(self):
        """
        姓名输入汉字、英文、数字字符
        1.register
        2.create team
        3.create_team_username
        """
        pics = []
        self.driver.register(self.mobile)
        exp = "true"
        res = self.driver.check_button_disabled()
        self.driver.allure_report(self.test_create_team_username, pics, exp, res)
        self.driver.Assert.assert_equal(exp, res)
Config 配置

一般配置host 等数据 使用ConfigParser读取写入
config.ini

[loginParam]
username = username
password = 123456

[domain]
cm = xx
class Config:

	def get_conf(self, title, value):
        """
        read .ini
        :param title:
        :param value:
        :return:
        """
        log.info("{} : {}:{}".format(self.get_conf.__name__, title, value))
        return self.config.get(title, value)

    def set_conf(self, title, value, text):
        """
        change .ini
        :param title:
        :param value:
        :param text:
        :return:
        """

        log.info("{} : {}:{}:{}".format(self.set_conf.__name__, title, value, text))

        self.config.set(title, value, text)
        with open(self.config_path, 'w+') as f:
            return self.config.write(f)
main 启动

使用sys.argv 获取命令行自定义参数

if len(sys.argv) > 3:
        runCase = sys.argv[1]  # P1 P2 P3 ALL  指定运行的用例等级
        if runCase != "ALL":
            case_path = f"-m={runCase}"
        xml = sys.argv[2] # 报告路径
        if xml:
            xml_report_path = xml
        BUILD_NUMBER = sys.argv[3]

    args = ["-s", "-v", "-n=auto", case_path, '--alluredir', xml_report_path, '--clean-alluredir']

    pytest.main(args=args)

pytest

pytest 有很多好用的功能、比如失败重跑、多进程并行用例、fixture 测试用例参数化等等
详见 gitHUB-SeleniumUIAuto 中的 readme

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1012411.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号