第七章 第四节 自动化测试高级应用之python多线程的使用

        有些读者可能会问为什么会在这儿突然加入python多线程/多进程的介绍呢?是为了效率,减少整个测试用例的执行时间。

        在web测试中,不可避免的一个测试就是浏览器兼容性测试,在没有自动化测试前,我们总是在一台或多台机器上安装N种浏览器,然后手工在不同的浏览器上验证主业务流程和关键功能模块功能,以检测在不同浏览器或不同版本浏览器上,我们的web应用是否可以正常工作。

        另外,当我们的项目测试用例比较多时,假设有500个用例,每个用例执行完需要30秒,那么整个项目的用例跑完就需要4个多小时,想想还是很慢的。

        这时如果我们引进多线程技术,那么理论上,每多开一个线程,测试时间就能节约一倍。本节就将具体介绍一下,多线程在我们自动化测试中的使用。

        但这块内容是真正的高级应用,理解起来会有点困难,包括笔者都理解的不是很透彻。所以,思来想去,决定只介绍一个容易使用,且易于理解的多线程解决方案

在使用多线程技术之前,我们首先要理解什么是线程?这里笔者给出两个学习链接,就不在这儿去一一介绍了。

        菜鸟教程关于多线程的介绍:Python3 多线程 | 菜鸟教程

        一位博友讲解的多进程多线程:搞定python多线程和多进程 - morra - 博客园

        对多线程不了解的读者朋友,还请先打开链接学习一下,然后继续后文的学习。

1、多线程在浏览器兼容性测试中的应用

        跨浏览器测试是功能测试的一个分支,用以验证web应用在不同浏览器上的正常工作,通常情况下,我们都期望web应用能够被我们的用户在任何浏览器上使用,例如有的人喜欢IE浏览器上使用,有的人喜欢Firefox或者有的人喜欢Chrome。但事实是,因为如下的部分原因,使得我们的web应用在这些浏览器上很多地方并不相互兼容。

  • 部分css样式在不同浏览器中显示是不一样的,比如最让人头疼的IE,是前端开发人员心中挥之不去的阴影;
  • Javascrpt在不同浏览器中实现方式不一样,例如某些点击后动作和点击后返回结果等;
  • 有的低版本浏览器不支持h5;
  • 图片位置大小问题、字体大小问题;
  • div、span...等标签float属性问题等;
  • 浏览器和操作系统间的兼容问题;

        以上几点轻微的是页面样式显示不一样,严重的会导致某些功能不可用。那么如何解决跨浏览器兼容性测试?下面我们基于Python的多线程技术来尝试启动多个浏览器进行自动化测试。我们以百度搜索为实例来介绍,代码如下:

from selenium import webdriver
import threading
import time


# 测试用例
def test_baidu(browser):
    driver = None
    if browser == 'ie':
        driver = webdriver.Ie()
    elif browser == 'firefox':
        driver = webdriver.Firefox()
    elif browser == 'chrome':
        driver = webdriver.Chrome()
    elif browser == 'edge':
        driver = webdriver.Edge()

    if driver is None:
        exit()

    driver.implicitly_wait(5)
    driver.get("https://www.baidu.com")
    driver.maximize_window()

    time.sleep(2)
    driver.find_element_by_id('kw').send_keys('selenium')
    driver.find_element_by_id('su').click()

    time.sleep(3)
    print("已在 {} 浏览器中执行完毕!".format(browser))
    driver.quit()

if __name__ == "__main__":
    browsers = ['ie', 'firefox', 'chrome', 'edge', 'opera']
    
    # 构建线程并启动执行
    for browser in browsers:
        th = threading.Thread(target=test_baidu, args=(browser,))
        threads.append(th)
        th.start()

        执行上面的脚本,我们会发现用例会在不同的浏览器中并行执行,相较手工测试,甚至比单线程测试要快很多,这就是多线程技术的魅力所在。

2、多线程在批量执行用例中的应用

        我们前面讲过,当需要执行大量的测试用例时,单线程的去跑用例,速度依然很慢。为此,我们引进多线程技术。笔者参考了很多关于多线程和多进程在自动化测试中应用的资料,综合比较下来,只发现一种方案是比较简单易用的,也是能很方便整合到我们原有已搭建好的自动化测试框架的。即引入新的可完美结合多线程技术的测试报告生成模块——BeautifulReport模块。

BeautifulReport模块下载地址:GitHub - TesterlifeRaymond/BeautifulReport: 适用于unittest自动化测试的可视化报告。下载好之后放到D:\Python37\Lib\site-packages目录下。

        BeautifulReport模块是GitHub上的一位大神和其好友共同开发的,可完美解决使用多线程技术测试时测试报告的生成问题。如果使用多线程技术进行自动化测试,我们前面介绍的生成测试报告的HTMLTestRunner模块将在此结束它的历史使命了,因为它不支持多线程技术在自动化测试中的使用(有兴趣的可以去尝试解决一下)。

        嗯~,笔者根据自己的喜好和对我们现有框架的适配,对BeautifulReport模块做了稍许优化,感兴趣的可以到我的资源下载优化过的BeautifulReport模块:BeautifulReport-Web服务器文档类资源-CSDN下载很方便整合到selenium自动化测试框架的,完美结合多线程技术的测试报告生成模块——Beautif更多下载资源、学习资料请访问CSDN下载频道.https://download.csdn.net/download/SCF_1104/74482493

优化如下:

  • 修复了【报告汇总】部分用例统计错误的BUG;
  • 去掉了【报告汇总】和【详细数据】两栏右侧[ x ]按钮
  • 实现了【报告汇总】和【详细数据】两栏右侧[ ^ ]符号的展开和收起功能
  • 将原有的title字段改为description字段,并新增title字段和tester字段;
  • 测试报告页面右下角新增了一个一键刷新置顶按钮;
  • 修改了截图存放路径,以适配我们现有的框架,截图路径:\web_auto\result\img;

        那么怎么使用这个模块呢?我们只需要重构一下run_allcase.py文件就好了,这就是框架中各个部分都模块化的好处,当代码需要改动时,只需改动相对应的模块就好了。

        具体的修改后的run_allcase.py代码如下:

from public.common import send_mail  # 引入public.common中邮件发送功能
from BeautifulReport import BeautifulReport  # 引入BeautifulReport模块
import unittest, time, os, threading

# 获取当前时间,并转化成我们想要的格式
now_time = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime(time.time()))
# 拼接测试报告名,固定名TestReport + 当前时间
report_name = 'TestReport_' + now_time + '.html'
# 拼接测试报告存放路径
report_path = os.path.join(os.getcwd(), 'result\\testreport')


# 使用discover方法加载所有test_开头的测试用例
def add_suite():
    case_file = os.path.join(os.getcwd(), 'testcase')
    discover = unittest.defaultTestLoader.discover(
        case_file,
        pattern='test_*.py',
        top_level_dir=None
    )
    return discover


# 调用BeautifulReport模块执行测试用例,并生成测试报告
def run_case(suites):
    result = BeautifulReport(suites)
    result.report(filename=report_name,
                  tester='非攻',
                  title='自动化测试报告',
                  description='百度、CSDN、慕课用例批量执行测试',
                  log_path=report_path
                  )


# 使用多线程去执行测试用例
def start_thread(suites):
threads = []
# 创建线程,并启动
    for test_case in suites:
        t = threading.Thread(target=run_case, args=(test_case,))
        t.start()
        threads.append(t)

    # 等所有线程完成用例执行
    for t in threads:
        t.join()


# 封装一个主函数
def main():
    test_suites = add_suite()
    start_thread(test_suites)

    # 所有用例执行完成后,将生成的测试报告通过邮件发送
    filename = '{}\\{}'.format(report_path, report_name)
    text = "最新Web自动化测试报告请接收,见附件。"
send_mail(text, filename)


if __name__ == "__main__":
	main()

        从上面代码我们可以看到,我们对run_allcase.py进行比较大的重构,重构的主要思路是对用例的读取加载、用例的执行、多线程的使用等分别进行封装,使代码逻辑更清晰、更有条理。

        执行一下我们新改造的run_allcase.py脚本,我们会看到三个用例文件test_baidu.py、test_imooc.py、test_csdn.py中的用例会同时执行,执行完毕会在testreport目录下生一个新的测试报告,如下图。同时我们的自动发送邮件功能,会把测试报告以附件的方式发送给你设定的接收者。

第七章 第四节 自动化测试高级应用之python多线程的使用_第1张图片

 有没有发现新的测试报告要比原来的更好看呢?关于多线程技术的使用就介绍到这儿了。不熟悉多线程的读者,还请先去学习了解一下多线程部分的知识,懂个基础就行了。

这部分学会实例中的用法就好,可以不去深究。

3、补充:BeautifulReport模块提供的截图功能

        此部分介绍的非多线程内容,前面有提到,BeautifulReport模块有一个截图功能,可以将截图放在测试报告对应的用例中,这个功能是极好的,所以在这里补充介绍一下。

        有时我们在测试中,当用例执行失败时,我们总希望在回溯失败用例的时候有依有据,这时候除了测试执行的日志,还需要有一个更直观的屏幕截图。在第五章第四节我们有介绍过截图的API,这里我们想要的是把截图整合到我们的测试报告中,该怎么实现?

        BeautifulReport模块提供了一个API——add_test_img(),在对应的测试用例外挂一个装饰器就好了。对于截图的存放,我们在result目录下新建一个img目录用于存放截图。那么如何使用这个截图功能呢?具体使用如下,我们以test_baidu.py中的用例改造示例。

from BeautifulReport import BeautifulReport  # 引入BeautifulReport模块
from selenium import webdriver
import unittest
import time, os


class TestBaidu(unittest.TestCase):
    img_path = 'result\\img'

    # 传入一个img_name(图片名), 并存储到默认的文件路径下(.\web_auto\result\img)
    def save_img(self, img_name):
        self.driver.get_screenshot_as_file(
'{}\\{}.png'.format(os.path.abspath(self.img_path), img_name)
)

    def setUp(self):
        self.driver = webdriver.Firefox()
        self.driver.implicitly_wait(10)
        self.driver.get("https://www.baidu.com")

    # 打开百度, 点击新闻按钮前截一次图,在点击新闻按钮后再截一次图
    # 这里add_test_img参数即相应的截图名称,必须要与save_img参数一致
    @BeautifulReport.add_test_img('点击新闻按钮前', '点击新闻按钮后')
    def test_news(self):
        """新闻按钮跳转"""
        self.save_img('点击新闻按钮前')
        self.driver.find_element_by_link_text('新闻').click()
        self.save_img('点击新闻按钮后')
        self.assertIn('百度新闻', self.driver.title)

    # 如果在测试过程中, 出现不确定的错误, 程序会自动截图, 并返回失败。
    # 此时add_test_img参数必须是用例方法名,这个名字也将是截图名
    @BeautifulReport.add_test_img('test_map')
    def test_map(self):
        """地图按钮跳转"""
        # 此处故意设置使定位失败
        self.driver.find_element_by_link_text('地图的').click()
        # 此处故意使校验失败
        self.assertIn('百度地图', self.driver.title)

    # 如果用例没有出现错误, 即使用了错误截图装饰器, 也不会影响用例的使用,也不会截图
    @BeautifulReport.add_test_img('test_academic')
    def test_academic(self):
        """学术按钮跳转"""
        self.driver.find_element_by_link_text('学术').click()
        self.assertIn('百度学术', self.driver.title)

    def tearDown(self):
        time.sleep(3)
        self.driver.quit()

        仔细阅读上面的改造过的test_baidu.py脚本代码,这里截图装饰器的使用,分了两种情况:

        一是已预知用例中某个地方可能出现错误,指定在预知出错地方前后调用截图save_img(),如脚本中的test_news()用例。这种情况装饰器的参数值要与save_img()中参数值一致,这个是作为截图名称的,一定要一致;

        二是不确定用例中哪儿会出现错误,只外挂一个装饰器,如脚本中test_map()和test_academic()两个用例。这种情况装饰器中的参数值要与测试用例方法名一致,同样的,这也是作为截图名称的。另外,若所挂装饰器的测试用例没有出错,则不会截图,对测试用例也不会有影响。

        改造完test_baidu.py脚本代码,我们执行run_allcase.py,用例跑完之后,我们会发现在\web_auto\result\img目录下多了三个截图,如下图。

第七章 第四节 自动化测试高级应用之python多线程的使用_第2张图片

         我们再打开新生成的测试报告,分别展开test_map 和 test_news用例,会发现下面也出现了对应的截图,如下两张图,这就是我们要的效果。

        但个人觉得,这个功能尽量少用,当用例多起来时,这个功能会出现一些不稳定的错误,另外加载的截图过多,也会导致测试报告页面加载卡顿。

第七章 第四节 自动化测试高级应用之python多线程的使用_第3张图片

第七章 第四节 自动化测试高级应用之python多线程的使用_第4张图片

你可能感兴趣的:(selenium3,+,自动化,python)