python自动化测试实战 —— 单元测试框架

简介: python自动化测试实战 —— 单元测试框架

软件测试专栏


实战相关知识

1.unittest框架

     unittest框架是Python语言内置的单元测试框架,Python编写的Web UI自动化测试脚本可以借助该框架来组织和执行。

(1)UnitTest组成部分

  • TestFixture(测试固件):测试用例的准备和销毁。
  • TestCase(测试用例):一个TestCase的实例就是一个测试用例。
  • TestSuite(测试套件):将多个测试用例集合在一起就是一个TestSuite。
  • TestRunner(测试运行器):使用TextTestRunner提供的 run( )方法执行测试用例。

(2)使用UnitTest测试框架注意:

  • 首先需要导入unittest包:import unittest。
  • 导入包的语句和定义测试类中间要隔两个空行。
  • 新建测试类的名称,建议每个单词的首字母大写,编写顺序建议保持团队一致。
  • 测试类必须继承unittest.TestCase
  • 接下来可以编写setUp,setUp方法不是必须需要的。
  • 接下来可以编写测试用例,测试用例名称以”test_”开头。
          self.assertXXX是UnitTest提供的断言方法
  • 用例写完,就可以编写tearDown,tearDown也不是必须要有。
         tearDown写完后空两行,就可以使用unittest.main()进行测试了。

(3)用HTMLTestRunner模块生成可视化测试报告。

2.Pytest测试框架

     Pytest测试框架在当今自动化测试中更受欢迎,是一个非常流行且成熟的全功能的Python测试框架,适用于单元测试、UI测试、接口测试。

(1)Pytest规则

  • 文件命名:默认以“test_”开头或者以”_test”结尾。
  • 测试类(class)命名:默认以“Test”开头
  • 测试方法(函数)命名:默认以“test_”开头
  • 断言:直接使用Python语言的断言assert

(2)Pytest测试固件

  • 如果测试文件中没有定义class,而是直接定义的函数,那么使用setup_module、teardown_module 和 setup_function、teardown_function
  • 如果测试文件中定义了class,就使用setup_class、teardown_class 和 setup_method、teardown_method
  • 不管是否定义class,都可以使用setup、teardown来实现在每个方法(或函数)的前后执行。
  • 建议在一个项目中约定好是定义class来组织测试用例,还是直接定义函数来组织用例。

(3)测试用例

     Pytest和unittest的框架风格基本一致,但有几点要注意:

  • 注意函数或方法名以“test_”开头
  • 直接通过函数定义测试用例的话,def后面的括号中没有self
  • 通过class中的方法定义测试用例的话,def后面的括号中有self。
  • 断言用的是Python的断言方式。

(4)用第三方插件完成测试报告的生成。

实战内容

1.“百度翻译”的页面UI测试

     将“百度翻译”的页面UI测试(至少包含翻译功能这个测试用例)的自动化测试线性脚本,分别用unittest和Pytest框架完成,并生成测试报告。

(1)利用unittest框架完成

首先需要导入包

新建测试类的名称,测试类必须继承unittest.TestCase

编写setUp

编写测试用例,测试用例名称以”test_”开头。

  • 用例1:输入的文字与语言不一致

    使用assertTRUE断言方法,断言网页会输出与输入文字匹配的语言,如下图

  • 用例2:输入的文字与语言一致

    使用assertEqual断言方法,断言输出文本框结果与预期结果一致,如下图

    用例写完,编写tearDown

    tearDown写完后空两行,使用unittest.main()进行测试

    用第三方插件完成测试报告的生成
    将HTMLTestRunner.py和run.py以及__init__.py文件放置与脚本文件同级目录下,如下图:

    编写run.py文件

    运行run.py文件
    运行结果如下

    出现如上结果,说明两个测试用例通过
    测试报告如下

(2)利用Pytest框架完成

首先需要导入包

新建测试类的名称,默认以“Test”开头

编写setUp

编写测试用例,测试用例名称以”test_”开头。

  • 用例1:输入的文字与语言不一致

    使用Python语言的断言assert,断言网页会输出与输入文字匹配的语言
  • 用例2:输入的文字与语言一致

    使用Python语言的断言assert,断言输出文本框结果与预期结果一致
  • 用例写完,编写teardown

    全局设置
    创建一个配置文件:pytest.ini
    该文件要和需要执行的测试文件所在的目录文件在同一级
    如下图所示:

    pytest.ini内容如下:

    通过addopts来设置命令行参数;-v 监控、失败重试的次数、重试的时间间隔、按标签来执行、生成测试报告,多个参数之间用空格分隔
  • 接着在py文件teardown后两行,使用pytest.main()进行测试

    运行结果如下

    出现passed说明两个测试用例通过
    测试报告如下

2.“新浪微博”的两个页面UI测试

     将“新浪微博”的两个页面UI测试(至少包含登录账号、发文字微博两个测试用例)的自动化测试线性脚本,分别用unittest和Pytest框架完成,并生成测试报告。

(1)利用unittest框架完成

首先需要导入包

新建测试类的名称,测试类必须继承unittest.TestCase

编写setUp,因为用例二需要登录才能进行测试,所以登录需要写进setUp

编写测试用例,测试用例名称以”test_”开头。

  • 用例1:登录账号,这里仅测试是否通过

    使用assertIn断言方法,断言用户名‘111Nuyoah111’会出现在网页中

  • 用例2:发布微博文字
    使用assertIn断言方法,断言发布内容成功,如下图

  • 用例写完,编写tearDown

  • tearDown写完后空两行,使用unittest.main()进行测试

    用第三方插件完成测试报告的生成
    将HTMLTestRunner.py和run.py以及__init__.py文件放置与脚本文件同级目录下,如下图:

  • 编写run.py文件

    运行run.py文件
    运行结果如下

    出现如上结果,说明两个测试用例通过
    测试报告如下

(2)利用Pytest框架完成

首先需要导入包

新建测试类的名称,默认以“Test”开头

编写setUp

编写测试用例,测试用例名称以”test_”开头。

  • 用例1:登录账号,这里仅测试是否通过

使用assertIn断言方法,断言用户名‘xxx’会出现在网页中

  • 用例2:发布微博文字

    使用assertIn断言方法,断言发布内容成功
  • 用例写完,编写teardown

    全局设置
    创建一个配置文件:pytest.ini
    该文件要和需要执行的测试文件所在的目录文件在同一级
    如下图所示:

    pytest.ini内容如下:

    通过addopts来设置命令行参数;-v 监控、失败重试的次数、重试的时间间隔、按标签来执行,多个参数之间用空格分隔
    运行生成测试报告,在py文件teardown后两行,使用pytest.main()进行测试

  • 运行结果如下

    出现passed说明两个测试用例通过
    测试报告如下

操作异常问题与解决方案

  • 问题1:pytest框架脚本运行失败
  • 解决方法:通过查询,发现是pytest环境问题,所以将pytest及相关插件卸载后在全局目录下重新下载

  • 问题2:allure在成功使用后,再次使用会自动跳过测试用例

  • 解决方法:allure环境不稳定,更换测试报告方法,使用pytest-html完成测试报告

  • 问题3:微博无法使用账号密码登录,测试用例无法完成登录的试错
  • 解决方法:修改代码,直接在setup固件进行手动登录,最后加入一个登录的测试用例进行断言

总结

     Unittest和Pytest是Python中常用的两个测试框架,用于编写和执行单元测试。

     Unittest是Python的内置测试框架之一,可以通过导入unittest模块来使用。Unittest提供了一组用于编写测试用例的类和方法,测试用例是通过继承unittest.TestCase类来创建的。测试方法以test_开头,并且可以使用断言方法(如assertEqual()、assertTrue()等)来验证预期行为。Unittest提供了丰富的功能和工具,如测试套件、测试装置(setUp()和tearDown()方法)、测试发现等。可以使用命令行工具或集成开发环境(IDE)来运行Unittest测试。

     Pytest是一个第三方的Python测试框架,可以通过安装pytest库来使用。Pytest提供了更简洁、灵活和可扩展的方式来编写测试用例。不需要继承特定的基类,可以使用普通的函数定义测试用例,用assert语句来断言结果。Pytest具有丰富的插件生态系统和许多附加功能,例如自动发现测试文件、参数化测试、夹具(fixtures)等。Pytest支持使用命令行工具来运行测试,并提供了丰富的输出和报告选项。

     unitest和pytest的区别是:语法风格:Unittest使用类和方法的方式来组织测试用例,而Pytest使用函数定义测试用例。灵活性:Pytest提供了更灵活和简洁的语法,没有像Unittest那样的约束。Pytest的编写方式更为简单,减少了样板代码的编写。插件生态系统:Pytest具有丰富的插件生态系统,提供了许多附加功能和扩展选项,而Unittest相对较少。自动发现测试:Pytest具有自动发现测试文件和用例的功能,而Unittest需要手动设置测试套件和加载用例。夹具支持:Pytest提供了强大的夹具(fixtures)机制,用于管理测试数据和环境设置。Unittest也支持夹具,但Pytest的夹具功能更为灵活和强大。

     总体而言,Pytest相对于Unittest提供了更简洁、灵活且功能更丰富的测试框架,能够简化测试代码的编写和维护,并提供更好的测试发现和报告功能。当然,选择使用哪个框架取决于个人偏好和项目需求。

附录

部分源码(与上面截图有所不同,仅供参考)

Baidu unittest

from selenium import webdriver
import unittest
from time import sleep
from selenium.webdriver.common.by import By
class TestBaidu(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(20)
        # 访问登录页
        self.driver.get('https://fanyi.baidu.com/')
        # 移除广告弹窗
        self.driver.find_element(By.CLASS_NAME,'app-guide-close').click()
    def test_001(self):
        # 用例一:输入的文字与选择的语言不一致
        # 选择语言阿拉伯语
        language = self.driver.find_element(By.CLASS_NAME,'select-from-language')
        language.click()
        language_text=self.driver.find_element(By.XPATH,'//*[@id="lang-panel-container"]'
                                                        '/div/div[5]/div[1]/div[1]/div/span[1]')
        language_text.click()
        #输入翻译文本英语
        intext =self.driver.find_element(By.CLASS_NAME,'textarea')
        intext.send_keys('love')
        sleep(2)
        # 输入不匹配文字后的提示信息
        self.assertTrue(self.driver.find_element(By.LINK_TEXT,'英语'))
    def test_002(self):
        # # 用例二:输入的文字与选择的语言一致
        # 选择语言英语
        language = self.driver.find_element(By.CLASS_NAME, 'select-from-language')
        language.click()
        language_text = self.driver.find_element(By.XPATH,'//*[@id="lang-panel-container"]'
                                                          '/div/div[5]/div[1]/div[21]/div/span[1]')
        language_text.click()
        # 输入翻译文本英语
        intext = self.driver.find_element(By.CLASS_NAME, 'textarea')
        intext.send_keys('love')
        sleep(2)
        # 输入不匹配文字后的提示信息
        outtext = self.driver.find_element(By.CLASS_NAME, 'output-bd').text
        self.assertEqual(outtext,'爱')
    def tearDown(self):
        self.driver.quit()
if __name__ == '__main__':
    unittest.main()

Baidu pytest

from time import sleep
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
class TestBaidu():
    def setup(self):
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(20)
        # 访问登录页
        self.driver.get('https://fanyi.baidu.com/')
        # 移除广告弹窗
        self.driver.find_element(By.CLASS_NAME,'app-guide-close').click()
    @pytest.mark.L1
    def test_001(self):
        # 用例一:输入的文字与选择的语言不一致
        # 选择语言阿拉伯语
        language = self.driver.find_element(By.CLASS_NAME,'select-from-language')
        language.click()
        language_text=self.driver.find_element(By.XPATH,'//*[@id="lang-panel-container"]'
                                                        '/div/div[5]/div[1]/div[1]/div/span[1]')
        language_text.click()
        #输入翻译文本英语
        intext =self.driver.find_element(By.CLASS_NAME,'textarea')
        intext.send_keys('love')
        sleep(2)
        # 输入不匹配文字后的提示信息
        assert '英语' == self.driver.find_element(By.LINK_TEXT,'英语').text
    @pytest.mark.L2
    def test_002(self):
        # # 用例二:输入的文字与选择的语言一致
        # 选择语言英语
        language = self.driver.find_element(By.CLASS_NAME, 'select-from-language')
        language.click()
        language_text = self.driver.find_element(By.XPATH,'//*[@id="lang-panel-container"]'
                                                          '/div/div[5]/div[1]/div[21]/div/span[1]')
        language_text.click()
        # 输入翻译文本英语
        intext = self.driver.find_element(By.CLASS_NAME, 'textarea')
        intext.send_keys('love')
        sleep(2)
        # 输入不匹配文字后的提示信息
        outtext = self.driver.find_element(By.CLASS_NAME, 'output-bd').text
        assert outtext=='爱'
    def teardown(self):
        self.driver.quit()
if __name__ == '__main__':
    pytest.main(["-s", "./test_baidu.py"])

Weibo unittest

from selenium import webdriver
import time,unittest
# 通过时间戳,构造唯一project name
from selenium.webdriver.common.by import By
project_name = 'project_{}'.format(time.time())
class TestNewProject(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(20)
        # 登录
        self.driver.get('https://weibo.com')
        self.driver.find_element(By.CLASS_NAME, 'LoginCard_btn_Jp_u1').click()
        time.sleep(8)  # 手动扫码登录
    def test_new_project(self):
        # 测试搜索框输入框
        self.driver.find_element(By.CLASS_NAME,'Form_input_2gtXx').send_keys('123')
        time.sleep(1)
        self.driver.find_element(By.CLASS_NAME,'Visible_angle_MP2Km').click()
        time.sleep(1)
        self.driver.find_element(By.XPATH,'//*[@id="homeWrap"]/div[1]/div/div[4]/div/div[3]/div/div/div[4]').click()
        # 测试发布
        self.driver.find_element(By.CLASS_NAME,'Tool_btn_2Eane').click()
        time.sleep(1)
        self.assertIn('123', self.driver.page_source)
    def tearDown(self):
        self.driver.quit()
if __name__ == '__main__':
    unittest.main()

Weibo pytest

import time
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
class TestWeibo  ():
    def setup(self):
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(20)
        # 登录
        self.driver.get('https://weibo.com')
        self.driver.find_element(By.CLASS_NAME, 'LoginCard_btn_Jp_u1').click()
        time.sleep(8)  # 手动扫码登录
    @pytest.mark.L1
    def test_new_project(self):
        assert 'xxx' in self.driver.page_source#此处自行修改“xxx”
        # 测试搜索框输入框
        self.driver.find_element(By.CLASS_NAME,'Form_input_2gtXx').send_keys('123')
        time.sleep(1)
        self.driver.find_element(By.CLASS_NAME,'Visible_angle_MP2Km').click()
        time.sleep(1)
        self.driver.find_element(By.XPATH,'//*[@id="homeWrap"]/div[1]/div/div[4]/div/div[3]/div/div/div[4]').click()
        # 测试发布
        self.driver.find_element(By.CLASS_NAME,'Tool_btn_2Eane').click()
        time.sleep(1)
        assert '123' in self.driver.page_source
    def teardown(self):
        self.driver.quit()
if __name__ == '__main__':
    pytest.main(["-s", "test_weibo.py", "--html=./report.html"])


目录
相关文章
|
3天前
|
测试技术 API 开发者
.NET单元测试框架大比拼:MSTest、xUnit与NUnit的实战较量与选择指南
【8月更文挑战第28天】单元测试是软件开发中不可或缺的一环,它能够确保代码的质量和稳定性。在.NET生态系统中,MSTest、xUnit和NUnit是最为流行的单元测试框架。本文将对这三种测试框架进行全面解析,并通过示例代码展示它们的基本用法和特点。
18 7
|
1天前
|
监控 测试技术 Python
软件测试的艺术与科学:探索测试自动化的奥秘
【8月更文挑战第30天】在软件开发的海洋中,测试是那把确保航船不偏离航线的罗盘。本文将带您一探究竟,从测试的基础到高级自动化策略,揭示如何通过代码和工具提升测试效率。准备好启航,因为我们将深入探讨软件测试的核心,以及如何利用自动化技术来优化您的测试流程。
11 4
|
1天前
|
物联网 测试技术 持续交付
软件测试的艺术与科学:探索自动化测试框架未来技术的融合与创新:探索区块链、物联网和虚拟现实的交汇点
【8月更文挑战第30天】在软件开发的海洋中,测试是确保航行安全不可或缺的灯塔。本文将带领读者揭开软件测试神秘的面纱,深入理解自动化测试框架的重要性和实现方法。通过实际案例,我们将一起探索如何构建高效、可靠的自动化测试系统,从而保障软件质量,提升开发效率。
|
2天前
|
测试技术
基于LangChain手工测试用例转Web自动化测试生成工具
该方案探索了利用大模型自动生成Web自动化测试用例的方法,替代传统的手动编写或录制方式。通过清晰定义功能测试步骤,结合LangChain的Agent和工具包,实现了从功能测试到自动化测试的转换,极大提升了效率。不仅减少了人工干预,还提高了测试用例的可维护性和实用性。
12 4
|
1天前
|
IDE Java 测试技术
揭秘Java高效编程:测试与调试实战策略,让你代码质量飞跃,职场竞争力飙升!
【8月更文挑战第30天】在软件开发中,测试与调试对确保代码质量至关重要。本文通过对比单元测试、集成测试、调试技巧及静态代码分析,探讨了多种实用的Java测试与调试策略。JUnit和Mockito分别用于单元测试与集成测试,有助于提前发现错误并提高代码可维护性;Eclipse和IntelliJ IDEA内置调试器则能快速定位问题;Checkstyle和PMD等工具则通过静态代码分析发现潜在问题。综合运用这些策略,可显著提升代码质量,为项目成功打下坚实基础。
|
1天前
|
监控 数据管理 jenkins
深入理解与应用软件自动化测试框架
【8月更文挑战第30天】在现代软件开发周期中,自动化测试已成为提高测试效率、保证软件质量的关键步骤。本文将探讨自动化测试框架的设计与实现,重点放在如何根据不同项目需求选择合适的测试框架,以及如何有效地集成到现有的开发和测试流程中。通过分析几个流行的自动化测试工具,如Selenium、Appium和JUnit,我们将讨论它们的特点、优势以及可能面临的挑战。此外,文章还将介绍一些最佳实践,帮助读者构建稳定且易于维护的自动化测试环境。
|
1天前
|
敏捷开发 测试技术 持续交付
软件测试中的自动化策略与实践云计算时代的网络安全挑战与对策
【8月更文挑战第30天】在软件开发的海洋中,自动化测试是一艘能够带领团队高效航行的帆船。本文将探讨如何搭建这艘帆船,从选择适合的自动化测试框架开始,到编写有效的测试脚本,再到持续集成的实施和测试结果的分析,我们将一步步揭开自动化测试的神秘面纱。你将学习到如何通过自动化测试来提升软件质量和开发效率,以及如何克服实施过程中的挑战。让我们一起启航,探索自动化测试的世界。
|
3天前
|
敏捷开发 Java jenkins
自动化测试框架的设计与实现
【8月更文挑战第28天】在软件开发的海洋中,自动化测试是一艘能带我们迅速穿越复杂代码波涛的快艇。本文将作为你的航海指南,不仅为你描绘出设计高效自动化测试框架的蓝图,还会提供实用的代码示例,让你能够亲自掌舵,驶向你的测试目的地。文章深入浅出,从基础概念讲起,逐渐深入到框架设计的核心理念和关键组件,最后通过一个具体的案例,展示如何将这些理论应用到实践中去。无论你是初涉测试领域的新手,还是寻求进阶的资深开发者,这篇文章都将为你打开一扇通往更高效、更智能测试世界的大门。让我们启航吧!
|
3天前
|
敏捷开发 测试技术 数据安全/隐私保护
自动化测试的高效之路:如何利用Python和Selenium提升测试效率
【8月更文挑战第28天】本文旨在探讨通过Python语言结合Selenium框架来提高软件测试的效率。文章不仅介绍了自动化测试的基本概念,还提供了具体的代码示例,帮助读者理解如何实现自动化测试脚本,并指出了在实施过程中可能遇到的问题及其解决方案。通过本文,读者将学会如何有效地使用Python和Selenium工具,以减少重复性工作,提升测试流程的效率与准确性。
|
1天前
|
传感器 物联网 测试技术
未来科技浪潮中的领航者:区块链、物联网与虚拟现实的融合与创新探索自动化测试之美——以Selenium为例
【8月更文挑战第30天】本文深入探讨了当前最前沿的技术趋势——区块链、物联网和虚拟现实,并分析了它们各自的发展脉络及相互之间的融合可能性。我们将通过具体应用场景描绘这些技术如何塑造未来社会的面貌,同时提供代码示例以加深理解。文章旨在为读者揭示这些技术背后的巨大潜力,以及它们将如何影响我们的工作和生活方式。
下一篇
云函数