• 0
  • 0
分享
  • 分析:如何多线程运行测试用例——软件测试圈
  • quinn 2022-08-02 16:07:00 字数 3941 阅读 1812 收藏 0

这是时常被问到的问题,尤其是UI自动化的运行,过程非常耗时,所以,所以多线程不失为一种首先想到的解决方案。

多线程是针对的测试用例,所以和selenium没有直接关系,我们要关心的是单元测试框架。

unittest

首先,应该说明的是unittest本身是不支持多线程的。当然,如果你学过Python的threading模块,也未必不行。不过我在stackoverflow 找了半天,大多是介绍unittest 测试多线程模块,并非是unittest本身如何多线程运行用例。

“我如何学习葵花宝典” 和 “我如何验证 张三 学会了葵花宝典”是两回事,而我显然要解决的问题是前者。

又重新百度,结果就找了答案。核心借助 tomorrow3 的测试库,再配合HTMLTestRunner 生成测试报告。

https://github.com/SeldomQA/HTMLTestRunner

https://github.com/dflupu/tomorrow3

1.png

  • 测试用例

测试用例如下,你可以复制多份测试。

# test_a.py
import time
import unittest
from selenium import webdriver

class Test1(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        cls.driver = webdriver.Chrome()
        
    def test_01(self):
        self.driver.get("https://www.bing.com/?mkt=zh-CN")
        elem = self.driver.find_element_by_id("sb_form_q")
        elem.send_keys("多线程")
        elem.submit()
        time.sleep(2)
        self.assertIn("多线程", self.driver.title)
        
    @classmethod
    def tearDownClass(cls):
        cls.driver.quit()
        
if __name__ == "__main__":
    unittest.main()
  • 运行文件

核心在tomorrow3提供的threads装饰器,用于装饰测试运行方法。
import unittest
import os
from TestRunner import HTMLTestRunner
from tomorrow3 import threads

# 定义目录
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
TEST_DIR = os.path.join(BASE_DIR, "test_dir")
REPORT_DIR = os.path.join(BASE_DIR, "test_report")

def test_suits():
    """
    加载所有的测试用例
    """
    discover = unittest.defaultTestLoader.discover(
        TEST_DIR,
        pattern="test_*.py"
    )
    return discover
    
@threads(2)  # !!!核心!!!! 设置线程数
def run_case(all_case, nth=0):
    """
    执行所有的用例, 并把结果写入测试报告
    """
    report_abspath = os.path.join(REPORT_DIR, f"result{nth}.html")
    with open(report_abspath, "wb+") as file:
        runner = HTMLTestRunner(stream=file, title='多线程测试报告')
        # 调用test_suits函数返回值
        runner.run(all_case)
        
if __name__ == "__main__":
    cases = test_suits()
    # 循环启动线程
    for i, j in zip(cases, range(len(list(cases)))):
        run_case(i, nth=j)  # 执行用例,生成报告

总结:

确实可以(根据设置的线程数)同时开启两个浏览器运行,同时带来了两个问题。

  1. 程序会根据线程数,生成多份测试报告,每个测试报告统计当前线程所运行的测试结果。

  2. 如果去掉nth参数,设置为一个报告,那么第二个线程运行的结果不能正确展示的一张报告上。

  3. 至少每个线程中的用例要保证有浏览器的启动/关闭。

第3点,你可能不理解,我举个例子,小时候见过妈妈/奶奶缝衣服。假设一件衣服拿一根针来缝制,缝衣服最麻烦就是穿针引线,针眼很小,每次都要费半天功夫,小孩子眼神好,我时常被叫去穿针引线。那为了节约时间怎么办,我当然是把线弄的长长的,最好是一根针线可以缝制多件衣服。

在Selenium 中,定义的浏览器驱动driver,每一条用例都定义一次驱动,伴随而来的就每个用例都开启/关闭一次浏览器,这当然是非常耗时的,为了缩短这个时间,我们最好是启动一次浏览器把所有用例都跑完才关闭。

那么问题来了,当我们使用多线程之后,相当于多个人同时缝制衣服,共用一根针线肯定不行啊。至少需要每人一根针线吧!而且缝制衣服的人是变化的,为了赶时间就多两个人(多开两个线程),用例比较少就少几个人(少启两个线程),为了适应这种变化,那么最好一件衣配置一根针线,每件衣服是最小单位,一个人必须要独立的把一件衣服缝好。

为了使用多线程,我们就必须每条用例开启/关闭一次浏览器,这其实是另一种时间的浪费,为了弥补这里的浪费,你必须把线程开得足够多才行。

最后,你必须再配置一位统计员,去统计每个人缝制衣服的数量,合计到一个报告中。

pytest

多线程运行用例在 pytest 中就相对容易太多了,pytest-xdist 插件就可以完成这件事情。

https://github.com/pytest-dev/pytest-xdist

2.png

  • 测试用例

测试用例如下,你可以复制多份测试。

# test_a.py
import time
from selenium import webdriver

def test_01():
    driver = webdriver.Chrome()
    driver.get("http://www.baidu.com")
    elem = driver.find_element_by_id("kw")
    elem.send_keys("unittest")
    elem.submit()
    time.sleep(2)
    assert driver.title == "unittest_百度搜索"
    driver.quit()
    
def test_02():
    driver = webdriver.Chrome()
    driver.get("http://www.baidu.com")
    elem = driver.find_element_by_id("kw")
    elem.send_keys("python")
    elem.submit()
    time.sleep(2)
    assert driver.title == "python_百度搜索"
    driver.quit()
  • 运行文件

核心就是安装 pytest-xdist 插件,通过-n参数设置线程数即可。

import os
import pytest

# 定义目录
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
TEST_DIR = os.path.join(BASE_DIR, "test_dir")
REPORT_DIR = os.path.join(BASE_DIR, "test_report")

if __name__ == '__main__':
    report_file = os.path.join(REPORT_DIR, "result.html")
    pytest.main([
        "-n", "2",  # !!核心!!!设置2个线程
        "-v", "-s", TEST_DIR,
        "--html=" + report_file,
        ])

总结:

相对于unittest,在pytest实现多线程非常简单,最终线线程的测试结果也可以很好在一个测试报告中展示。

  1. 存在的问题,正如我上面讨论的,你必须为每个用例设置开启/关闭。除了额外消耗启动时间外,如果想统一配置用例通过哪个浏览器执行也会比较麻烦。

  2. 你的每一条用例应该保持绝对独立,不能出现这条用例依赖上条用例的执行结果。因为,这两条用例可能会分配由不同的线程执行。

  3. 正如上一条的原因,你不能控制用例的执行顺序。


作者:虫师

原文链接:https://www.cnblogs.com/fnng/p/15441515.html

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • 一、概述所谓回归测试就是当软件发生改变时,重新测试已经通过测试的测试区域,以验证修改的正确性及其影响。在软件开发生命周期中,软件发生改变,就会带来问题,改变可能是源于发现了错误并做了修改,也有可能是因为集成或维护阶段加入了新模块。错误跟踪与管理系统不完善,对错误的理解不透彻,只修正了错误的外在表现,从而造成修改失败;修改还有可能产生副作用,从而导致软件未被修改的部分产生新的问题;新加入的代码还有可能对原有代码带来影响。因此,我们就必须重新测试,以便确定修改是否达到了预期的目的。同时,为了验证修改的正确性及其影响就需要进行回归测试。回归测试作为软件生命周期的一个组成部分,在整个软件测试过程中占有...
            1 0 1315
            分享
          • 读者提问:『阿常你好,想请教一下,测试研发的人数科学比例应该是多少呢 ?』阿常回答:没有标准的参考比例,每个团队的实际情况不一样。比如,我们可能需要考虑的几个因素:1、软件的易测试程度2、测试人员和开发人员的经验3、必须坚持的质量标准4、研发测试流程成熟度阿常碎碎念:以上,代表阿常个人观点。看完今天的分享对你是不是有所启发呢,有任何想法都欢迎大家后台私信阿常,一起探讨交流。
            0 0 961
            分享
          • 读者提问:有没有一款工具是集 API 文档、API 调试、API Mock、API 自动化测试四种功能为一身的 ?公司现状是这样:开发定义 API 使用 Swagger,后端开发调试 API 使用 Postman,前端 API 数据 Mock 使用 RAP,测试做 API 自动化测试或压力测试使用 Jmeter。开发团队协同效率很低,接口变更了往往做不到各方同步,很让人崩溃。阿常回答:有,Apifox。Apifox 就是 API 文档、API 调试、API Mock、API 自动化测试一体化协作平台,定位 Postman + Swagger + Mock + JMeter。官网链接:https...
            0 0 988
            分享
          •   在业务系统逻辑实现中,经常涉及异步执行、异步更新场景的开发和使用。但在性能测试中,经常会出现因为异步逻辑设计不合理引发的不可预知问题,比如在开发验证时一切正常,测试人员在性能测试时偶发报错。  本文从Spring事务、业务逻辑顺序、数据库死锁等方面介绍在项目研发中遇到的几种异常场景供读者学习。  一、事务延迟提交引发的异步执行偶发问题分析和设计思考。  1、场景说明:当前有两个线程A、B,A是生产者,B是消费者,A、B两个线程异步执行,A每次从队列获取n条待处理任务,然后依次处理每条任务,包括业务逻辑处理、远程过程调用、更新数据库、将任务放入消费者队列,B从消费队列获取任务进行处理。  2...
            0 0 148
            分享
          •   想学习开源框架也已经很长时间了,工作中都是使用商业软件,很少有机会能够尝试开源软件项目,经过一段时间的调整,也抽空把开源框架渐渐了解熟悉起来。  很多项目都在使用UI Automation工具Selenium,一个成熟应用并且版本来到4.0的开源框架,很好的能够完成UI测试工作。  Robot framework是什么  Robot framework它是什么,它其实就是在Selenium基础上进行二次开发,能够将常用方法、常用框架比如关键字驱动、数据驱动、行为开发驱动集合在一起的开源框架。  它的特点是能够将函数封装起来,降低开发成本,规范开发样式,将我们需要反复封装的函数进行了整合,并...
            14 14 1251
            分享
      • 51testing软件测试圈微信