web自动化测试进阶篇01 ——— 策略模式的实践与技巧

news2024/11/24 5:52:13

在这里插入图片描述

 
 

在这里插入图片描述
😏作者简介:博主是一位测试管理者,同时也是一名对外企业兼职讲师。
📡主页地址:【Austin_zhai】
🙆目的与景愿:旨在于能帮助更多的测试行业人员提升软硬技能,分享行业相关最新信息。
💎声明:博主日常工作较为繁忙,文章会不定期更新,各类行业或职场问题欢迎大家私信,有空必回。

在这里插入图片描述

 
 

阅读目录

  • 1. 目的
  • 2. 策略模式
  • 3. 优势
  • 4. 实操
    • 4.1 拆解
    • 4.2 举一反三
  • 5. 后话

1. 目的

在这里插入图片描述
  web自动化测试作为软件自动化测试领域中绕不过去的一个“香饽饽”,通常都会作为广大测试从业者的首选学习对象,相较于C/S架构的自动化来说,B/S有着其无法忽视的诸多优势,从行业发展趋、研发模式特点、测试工具支持,其整体的完整生态已经远远超过了C/S架构方面的测试价值。

  经过前几次的大致讲解,我们已经将web自动化测试相关的基础知识介绍完了,相信大家如果一路学习过来的话,基本已经可以自己编写一个完整的UI自动化测试脚本与大致的框架了。

  接下来博主将会与大家讨论一些我们在设计与编写过程中会用到的进阶知识与技巧,通过这些相关的知识和技巧,就可以让我们的脚本与框架变得更为灵活与高效,那么我们就来看看今天要介绍的内容吧。

 
 

2. 策略模式

在这里插入图片描述
  看到这里,许多同学都会问,策略模式是什么?其实策略模式在自动化测试中是一种行为设计模式,说人话就是我们设计一套规则,来告诉程序什么时候或者什么条件下该执行什么样的操作。听到这里,估计又有同学会问,那这个不就是我们语法中的if-else吗?其实不单单是这样,具体的博主后面会详细介绍,这里大家只需要了解这个概念与我们测试计划中的测试策略大致相同,什么样的测试场景用什么样的测试数据,什么样的被测对象形态用什么样的测试用例,基本都是这样的概念了。

 
 

3. 优势

在这里插入图片描述
  策略模式与if-else能实现的效果是一致的吗?其实不然,光这样想就太片面了。要说优势之前,我们先来介绍一下策略模式的实现步骤:

  • 我们先需要定义一个抽象类,当然也可以是接口,里面一般含有执行动作或测试方法
  • 在类中编写具体的测试实现方法,实现类的功能
  • 创建策略对象,传递到对应的测试方法内
  • 最后实例化并调用策略,执行对应的测试方法

  相较于if-else来说,我们先将对应的规则设计好,再封装到独立的类中去,达到规则的实现与使用分离的效果。那么在执行的时候,测试同学可以灵活的使用各类规则来应对测试执行中会出现的多种测试场景。这是其一,其二,我们这样的设计理念,可以省去业务代码中的大量判断与分支,无论是从脚本框架的维护和扩展性上来说,策略模式有着绝对的优势。

 
 

4. 实操

在这里插入图片描述
  为了让大家更好的理解策略模式的实现,这里我们举个例子,来实际看看其中的基础概念。

from abc import ABC, abstractmethod

class TestStrategy(ABC):
    @abstractmethod
    def execute_test(self, url):
        pass

class ChromeTestStrategy(TestStrategy):
    def execute_test(self, url):
        # 执行Chrome浏览器测试
        pass

class FirefoxTestStrategy(TestStrategy):
    def execute_test(self, url):
        # 执行Firefox浏览器测试
        pass

class SafariTestStrategy(TestStrategy):
    def execute_test(self, url):
        # 执行Safari浏览器测试
        pass

class EdgeTestStrategy(TestStrategy):
    def execute_test(self, url):
        # 执行Edge浏览器测试
        pass

class TestRunner:
    def run_test(self, url, test_strategy):
        test_strategy.execute_test(url)

  从上面的代码来看,我们定义了一个TestStrategy抽象类,它用来执行测试用例。接下来封装了ChromeTestStrategy、FirefoxTestStrategy、SafariTestStrategy和EdgeTestStrategy类,其作用就是根据不同的测试要求与场景来切换不同的浏览器。TestRunner类用来接收一个URL和一个测试策略对象,并在方法内部调用测试策略对象的execute_test()方法来执行测试。

  相信大家都已经看懂了上面的一个小例子了,同时也对策略模式的有了一个大概的认知。那么在我们的日常工作中如何把策略模式融入其中呢,别急,接下来博主就来仔细的来进行拆解说明。

 

4.1 拆解

  我们日常写UI自动化测试用例,一般都会是以下的这种方式:

import unittest
from selenium import webdriver

class TestSearch(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.get("https://www.test.com/")

    def test_search(self):
        search_box = self.driver.find_element_by_name("input")
        search_box.send_keys("hello")
        search_box.submit()
        self.assertIn("hello", self.driver.title)

    def tearDown(self):
        self.driver.quit()

 
  这个就不具体介绍了,懂的自然懂,那么我们就把策略模式的理念加入到具体的脚本中来。

class SelectByBrowser(Strategy):
    def __init__(self, browser):
        self.browser = browser

    def select(self, suite):
        loader = unittest.TestLoader()
        browser_suite = loader.loadTestsFromTestCase(TestSearch)

        if self.browser == 'chrome':
            return browser_suite
        elif self.browser == 'firefox':
            return unittest.TestSuite()
        else:
            raise ValueError("无效的浏览器类性")

  上述的代码是一个名为SelectByBrowser的策略类,它的作用是接受一个浏览器参数(指定浏览器的类型),并返回一个包含测试用例的测试套件,该测试套件会根据所提供的浏览器参数选择测试用例。我们可以看到这里的选择方法中会进行对应的浏览器类型判断,如果是谷歌浏览器则会使用TestSearch的测试用例,而选择火狐浏览器则返回一个空的测试用例套件。

 

class SelectByEnvironment(Strategy):
    def __init__(self, environment):
        self.environment = environment

    def select(self, suite):
        loader = unittest.TestLoader()
        environment_suite = loader.loadTestsFromTestCase(TestSearch)

        if self.environment == 'dev':
            return environment_suite
        elif self.environment == 'prod':
            return unittest.TestSuite()
        else:
            raise ValueError("无效的环境类型")

  这个策略类会根据我们给出的环境参数(environment),返回对应的测试用例套件,以便我们可以针对不同的测试环境来灵活切换对应的测试用例,同样的选择开发环境的话返回TestSearch测试用例,选择生产环境的话依旧是返回空的用例套件。

 

class TestExecutor:
    def __init__(self, suite):
        self.suite = suite

    def execute(self):
        runner = unittest.TextTestRunner()
        return runner.run(self.suite)

  这里定义了个TestExecutor类,它的作用为接受一个测试套件并提供一个execute()方法来执行测试。通过这个类,我们可以根据SelectByBrowser和SelectByEnvironment的选择,让他们选择要执行的测试用例。

 

  这样大致就将策略模式的相关接口与测试用例主备好了,之后我们可以直接开始调用其进行实例化和使用了,这里为了方便演示与讲解,博主直接使用主程序的写法来进行调用,就不跨脚本了。

if __name__ == '__main__':
    suite = unittest.TestSuite()
    suite.addTest(TestSearch('test_search'))

    executor = TestExecutor(suite)

    # 在谷歌浏览器内执行的用例
    browser_strategy = SelectByBrowser('chrome')
    browser_suite = browser_strategy.select(suite)
    browser_executor = TestExecutor(browser_suite)
    browser_executor.execute()

    # 在开发环境中执行的用例
    env_strategy = SelectByEnvironment('dev')
    env_suite = env_strategy.select(suite)
    env_executor = TestExecutor(env_suite)
    env_executor.execute()

  在这个主程序中,先创建了一个包含测试用例的测试套件,然后将TestExecutor实例化,并将该测试套件传递给它。接下来,创建SelectByBrowser策略实例,并使用它选择Chrome浏览器的测试用例,而另一个TestExecutor实例来执行这些测试用例。接着创建一个SelectByEnvironment策略实例,并指定使用开发环境的测试用例,最后使用第三个TestExecutor实例来执行这些测试用例。

 

4.2 举一反三

  有了上面的例子,我们在日常的脚本设计中就可以进行有效的练习与运用,其实该设计行为的主旨很明确,你根据预先的测试设计与场景条件进行规则的创建,然后封装类或接口,调用。就是这么的简单,真正要说有点难度的则是在设计时期受否真正的将各种场景与策略考虑完全的情况,这个需要各位同学反复的去进行实践和总结。

  就拿博主自身来说,如果在测试项目的前期,我要对已经迭代后的自动化测试框架进行策略模式的优化,那么我就需要先将被测对象的相关业务场景和业务路线进行整理,这里需要注意的是尽量将异常场景进行排除,本就异常的结果会令自动化测试的结果发生不可预测的偏差。那么整理完上述的这些因素之后,将已知的业务场景与业务线路结果转化为具体的抽象类或接口,进行编写。

  假设这里的业务场景和测试需求为:私人基金公司管理着多个基金,每个基金都有不同的投资策略和风险水平。我们需要编写一套自动化测试来验证每个基金的投资策略是否符合预期,并且能够自动化地选择和执行不同的测试用例套件,以确保每个基金的投资策略都能够得到充分的测试和验证。

class SelectByRiskLevel:
    def __init__(self, risk_level):
        self.risk_level = risk_level

    def should_select(self, test_case):
        if test_case.risk_level == self.risk_level:
            return True
        else:
            return False

class FundInvestmentTestCase:
    def __init__(self, fund_id, investment_strategy, risk_level):
        self.fund_id = fund_id
        self.investment_strategy = investment_strategy
        self.risk_level = risk_level

class FundInvestmentTestExecutor:
    def __init__(self, test_cases):
        self.test_cases = test_cases

    def select_tests(self, selector):
        selected_tests = []
        for test_case in self.test_cases:
            if selector.should_select(test_case):
                selected_tests.append(test_case)
        return selected_tests

    def run_tests(self, test_cases):
        for test_case in test_cases:
            # Run test case
            pass

# 为不同的基金创建测试用例
test_cases = [
    FundInvestmentTestCase(fund_id=1, investment_strategy='Aggressive Growth', risk_level='High'),
    FundInvestmentTestCase(fund_id=2, investment_strategy='Balanced Portfolio', risk_level='Medium'),
    FundInvestmentTestCase(fund_id=3, investment_strategy='Conservative Income', risk_level='Low'),
    FundInvestmentTestCase(fund_id=4, investment_strategy='Value Investing', risk_level='High')
]

# 创建测试执行对象FundInvestmentTestExecutor
executor = FundInvestmentTestExecutor(test_cases)

# 选择测试用例来执行
risk_level_selector = SelectByRiskLevel('High')
selected_suite = executor.select_tests(risk_level_selector)
executor.run_tests(selected_suite)

  在上面的代码中,先定义一个SelectByRiskLevel策略类,用于根据风险水平选择测试用例套件。而FundInvestmentTestCase类,则表示不同的基金投资策略,包括基金ID、投资策略和风险水平。FundInvestmentTestExecutor类,用于选择和执行测试用例。

  因为测试业务与需求的要求,所以得创建一组不同的测试用例,表示不同的基金投资策略和风险水平。接着将FundInvestmentTestExecutor实例化,并将这些测试用例作为参数传递给它,其次使用SelectByRiskLevel策略类选择高风险水平的测试用例,而FundInvestmentTestExecutor的select_tests方法则会选择测试用例套件。最后由FundInvestmentTestExecutor的run_tests来执行具体的测试用例。

 
 

5. 后话

在这里插入图片描述
  在我们的日常工作中,策略模式因其特有的灵活特性,经常会让测试同学忘记了其原有的一些限制,其实代码中的设计也好,实现也罢,还是需要遵循UI自动化测试的一些基本规则。如果被测对象功能原本就不太稳定或经常发生业务、设计变更,依然是不推荐使用该模式。另外对于各类策略类的封装,远远没有博主上面演示的那么简单,需要好好考虑业务上下衔接的连贯性和稳定性,良好的上下文封装会让测试脚本的复用性大大提升,从而真正的达到提升测试与运行效率的目的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/508493.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【rust】| 02——语法基础_变量(不可变?)和常量

系列文章目录 【rust】| 00——开发环境搭建 【rust】| 01——编译并运行第一个rust程序 【rust】| 02——语法基础_变量(不可变?)和常量 文章目录 1. 变量1.1 变量的定义1.2 试验变量的不可变特性 2. 常量2.1 常量的定义 3. 覆盖(同名变量)3.1 修改已定义变量的数据类型3.2 1…

第5章 负载均衡

第5章 负载均衡 5.1 proxy_pass详解 在nginx中配置proxy_pass代理转发时,如果在proxy_pass后面的url加/,表示绝对根路径;如果没有/,表示相对路径,把匹配的路径部分也给代理走。 假设下面四种情况分别用 http://192.…

深度学习与文本聚类:一篇全面的介绍与实践指南

❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️ 👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…

vivado手写ROM改IP核

一、引言 手写了一个ROM,用于ADC或者DAC的寄存器配置。DAC出来的波形总是有两个对称的小肩膀,找不到原因。时序没有报错,但是有延迟。之前听同事说他们也遇到过这样的问题,是时序问题。所以,我也想试一下&#xff…

杂谈系列:唐高祖~开元通宝

唐高祖李渊(566年12月 -635年6月 ),字叔德。中国唐朝开国皇帝(618年6月18日-626年9月4日在位)。 作为唐朝开国的帝王,史学界对李渊的评价不一。有观点认为他优柔失断,赏罚…

源码级别讲解 redis 底层数据结构

redis 底层数据结构 Redis作为Key-Value存储系统,数据结构如下: Redis没有表的概念,Redis实例所对应的db以编号区分,db本身就是key的命名空间。 比如:user:1000作为key值,表示在user这个命名空间下id为10…

二叉树的层级遍历以及[NOIP2015 普及组] 扫雷游戏、有效时间的数目

一、二叉树的层级遍历 二叉树的层级遍历看着比其他遍历简单,但是我感觉实施起来却比其他遍历难,它主要是通过队列实现的 比如在这样的一颗二叉树中 我没先将a入队 队列:a 当a出队的时候就将它的左儿子和右儿子入队 队列&…

一图看懂 toml 模块:用于解析和创建TOML(Tom‘s Obvious, Minimal Language)的Python库, 资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创,转载请声明。 链接: https://blog.csdn.net/Ahcao2008 [TOC](一图看懂 toml 模块:用于解析和创建TOML(Tom’s Obvious, Minimal Language)的Python库, 资料整理笔记(大全)) ☘️摘要 全文介绍系统内置…

leap模型重点关注技术,如:能源结构清洁转型、重点领域如工业、交通节能减排降耗、新能源发电系统及发电成本最优化、区域碳达峰碳中和实现路径设计及政策评估

模型简介: 中文名:LEAP模型 外文名:Long Range Energy Alternatives Planning System/ Low emission analysis platform 采用部门分析法建立的LEAP模型(长期能源可替代规划模型)是一种自下而上的能源-环境核算工具&a…

Spark大数据处理讲课笔记3.8 Spark RDD典型案例

文章目录 零、本节学习目标一、利用RDD计算总分与平均分(一)提出任务(二)准备工作1、启动HDFS服务2、启动Spark服务3、在本地创建成绩文件4、将成绩文件上传到HDFS (三)实现步骤1、打开RDD项目2、创建计算总…

FS2455高效率的同步降压DC-DC转换器5A输出电流

概述 FS2455是一种高效率的同步降压DC-DC转换器,具有5A输出电流。 FS2455在4.5V到30V的宽输入电压范围内工作, 集 成主开关和同步开关,具有非常低的RDS(ON)以最小化传导损失。 FS2455具有轻载时的应用和高效率。此外…

[GFCTF 2021]文件查看器(GZ、过滤器、phar) day4

打开界面直接一个登录界面&#xff0c;直接admin/admin登录进去 。 进来之后发现是一个文件查看器的功能 随便输入了点东西发现了报错&#xff0c;然后读取文件的功能&#xff0c;输入Files.classs.php发现读取不成功 换了个index.php <?phpfunction __autoload($classN…

无效的目标发行版: 11

背景&#xff1a;最近在研究es&#xff0c;想着弄一个连接es集群的springboot的工程&#xff0c;然后就在网上找到一个&#xff0c;结果弄到本地运行时&#xff0c;报错了“ 无效的目标发行版: 11 ” 看着报错就知道肯定是你导入的项目和你本地的JDK版本不匹配了&#xff0c;然…

手把手教你如何将安卓手机数据导入iPhone!【详解】

案例&#xff1a;安卓数据导入苹果手机 【大神们&#xff0c;刚换了新的苹果手机&#xff0c;原本的安卓手机数据怎么导入新手机&#xff1f;】 想要换用iPhone&#xff0c;但是又不想丢失安卓手机里的重要数据怎么办&#xff1f;如何将安卓手机数据导入iphone&#xff1f;本文…

如何学习5G网络优化才能拿高薪?我已摆烂,各位努力!

“内卷”和“躺平” 有的人卷成了麻花 有的人选择了躺下 毕竟只要躺得够平&#xff0c;就卷不到我 但是更多的人选择在“内卷”与“躺平”的徘徊抉择中 “躺”的核心是休息&#xff0c;“卷”的本质是提升 但是在优橙教育学习5G网络优化 大家学会将两者融合 学习的时候…

玩转ChatGPT:快速制作PPT

一、写在前面 首先还是让小Chat推销下自己&#xff1a; 你是否曾经为制作 PPT 而烦恼&#xff1f;现在有了 ChatGPT&#xff0c;再也不必担心灵感枯竭啦&#xff01;使用 ChatGPT 撰写 PPT 可以让你轻松地组织思路、快速得到内容&#xff0c;无需任何营销口号&#xff0c;Cha…

【算法与数据结构】队列

队列 队列&#xff1a;结构定义 队列是有一篇连续的存储区&#xff0c;其实连续性不重要&#xff0c;而是队列需要保持一个特性&#xff1a; 从队首出元素&#xff0c;从队尾入元素。这一点与顺序表不一样&#xff0c;元素加入的位置不一样 队列&#xff1a;只允许从尾部加入…

P1003 [NOIP2011 提高组] 铺地毯

题目提供者 CCF_NOI 难度 普及- 此篇必须看到底&#xff01; 题目描述 为了准备一个独特的颁奖典礼&#xff0c;组织者在会场的一片矩形区域&#xff08;可看做是平面直角坐标系的第一象限&#xff09;铺上一些矩形地毯。一共有 n 张地毯&#xff0c;编号从 1 到 n。现在…

电力物联网是什么?在智能配电系统中有什么作用?

摘要&#xff1a;在社会经济和科学技术不断发展中&#xff0c;配电网实现了角色转变&#xff0c;传统的单向供电服务形式已经被双向能流服务形式取代&#xff0c;社会多样化的用电需求也得以有效满足。随着物联网技术的发展&#xff0c;泛在电力物联网开始应用于当今的电力系统…

便携式挂钩型儿童椅 标准ASTMF1235测试项目周期多久?

便携式挂钩型儿童椅 适用于6 个 月至 3 岁之间的儿童&#xff0c;体重不超过 37 磅&#xff0c;并具 备自主协调坐姿的能力。 那么该类产品上亚马逊需要做下面的检测&#xff1a; 便携式儿童外出餐椅 ASTM F1235-18 和 CPSIA&#xff08;铅、邻苯二甲酸盐&#xff09; 亚马逊…