前端测试 "二战" UI 测试 之 代码设计

泰斯特 · 2021年01月27日 · 最后由 泰斯特 回复于 2021年01月28日 · 3497 次阅读

背景

UI 自动化测试一直是老生常谈的话题,

作为处于"金字塔顶端"的自动化手段,用的不好就是一场灾难,用的好也无法雪中送炭。

在本篇文章中,我将记录一下我"第二次"设计 UI 测试的心得体会。

正文

POM(页面对象模型)相信大家已经非常熟悉了,核心思想就是每个页面对应一个类,在每个类中放置页面中的定位信息以及相关操作函数。

然而在 POM 的基础上,我们其实可以将每个页面的操作抽象成字典映射。这样一来,所有的用例执行对应的操作会变得非常清晰。

self.actions_map = {
    '点击职位管理标签': self._click_job_position_management_tab,
    '点击新增职位按钮': self._click_add_job_position_button,
    '输入职位信息': self._input_job_position_info,
}

在实战中,也相信大家发现不少页面带有重复的元素,比如标签栏,导航栏等通用组件。

针对这个情况,我们可以设计一个页面基础类,储存所有页面通用的 基础操作通用定位,所有独立的页面类都可以继承这个基础类,从而使得代码架构变得更加整洁,有效减少重复代码。

class PageObjectModel:

    LOCATORS = {
        'el-message--success': {'css selector': '.el-message--success'},
        'bread_crumb_nav': {'css selector': 'div[role=\'navigation\']'},
    }

    def __init__(self, browser=None):
        self.browser = browser
        self.actions_map = {}
        self.base_actions_map = {
            '检查并激活主页面包屑导航': self._check_and_activate_tab_bar,
            '切换至新开窗口': self._switch_to_new_window,
            '关闭当前窗口': self._close_current_window,
            '关闭新开窗口': self._close_new_window,
        }

    def operate(self, action, **kwargs):
        if action in self.actions_map.keys():
            self.actions_map[action](**kwargs)
        elif action in self.base_actions_map.keys():
            self.base_actions_map[action](**kwargs)
        else:
            preporter.warn(msg=f'action: 【{action}】 不在 action_map 内!')

这里的设计关键有两点:

  1. 初始化 base_actions_map,也就是我们的基础操作字典,我们要在这里对所有的测试执行步骤和对应的执行函数进行映射。

  2. 实现 operate 方法,所有的用例执行操作步骤都将通过 operate 方法 优先 在本身的操作字典中寻找映射函数。

基础类设计完毕~。

假设我们现在需要对某个页面做 UI 自动化,我们的只需要继承刚刚实现 PageObjectModel,
然后构造 actions_map 就可以了~

class JobPositionManagement(PageObjectModel):

    LOCATORS = {
        # 职位管理列表页元素
        'job_position_management_page': {'tag name': 'li', 'text': '职位管理'},
    }

    def __init__(self, browser=None):
        super(JobPositionManagement, self).__init__(browser)

        self.actions_map = {
            '点击职位管理标签': self._click_job_position_management_tab,
        }

    def _click_job_position_management_tab(self, browser=None):
        _browser = self.browser if self.browser else browser
    _browser.v_click(locate_rule=self.LOCATORS['job_position_management_page'])

最后在实际测试调用中,代码会变得非常整洁清晰,而这也是程序设计的魅力。

@HistoricalLogsDeletion
   @Test(enabled=False, tags=["职位管理", "回归测试", "冒烟测试"], description="验证点击【生成JD】后,JD输入框是否生成数据", timeout=30)
   def test_06(self):

       self.job_position_management.operate(action='生成JD')

       self.job_position_management.operate(action='等待页面加载完毕')

       self.job_position_management.operate(action='验证JD输入框内是否存在数据')

结尾

虽然大部分公司都无法成功在 UI 自动化测试中获得正收益,但测试技术的发展永无止境~

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 6 条回复 时间 点赞

有点关键字封装的意思了

很不错 学习到了

Jerry li 回复

概念是一样的,只不过这个封装的是个大的自定义的步骤~

咸鱼菜鸡 回复

👍

一点建议,能不能把 action 里的直接带出来,而不是写出来

redbiscuit 回复

当然可以的,你写在数据库去读也可以。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册