【软件测试】测试框架(unittest/pytest)

本文介绍了Python 中最常用的两个测试框架:unittestpytest,帮助你编写更规范、可维护的自动化测试用例。

一、unittest 框架

unittest 是 Python 内置的标准库,无需额外安装,适合初学者入门。它借鉴了 JUnit 的设计理念,提供了测试用例、测试套件、断言等基本功能。

1. 基本概念
  • TestCase :测试用例的基类,每个测试方法必须以 test_ 开头
  • TestSuite:测试套件,用于组织多个测试用例
  • TestRunner:测试运行器,执行测试并生成结果
  • Assertion:断言,验证测试结果
2. 简单示例

下面是一个使用 unittest 测试登录功能的示例:

python 复制代码
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By

class TestLogin(unittest.TestCase):
    def setUp(self):
        # 每个测试方法执行前运行,初始化浏览器
        self.driver = webdriver.Firefox()
        self.driver.get('https://example.com/login')
        self.driver.implicitly_wait(10)

    def tearDown(self):
        # 每个测试方法执行后运行,关闭浏览器
        self.driver.quit()

    def test_successful_login(self):
        # 测试成功登录的场景
        username = self.driver.find_element(By.ID, 'username')
        password = self.driver.find_element(By.ID, 'password')
        login_button = self.driver.find_element(By.ID, 'login-button')

        username.send_keys('valid_username')
        password.send_keys('valid_password')
        login_button.click()

        # 断言登录成功后页面上存在欢迎消息
        welcome_message = self.driver.find_element(By.CLASS_NAME, 'welcome-message')
        self.assertIn('欢迎', welcome_message.text)

    def test_failed_login(self):
        # 测试失败登录的场景
        username = self.driver.find_element(By.ID, 'username')
        password = self.driver.find_element(By.ID, 'password')
        login_button = self.driver.find_element(By.ID, 'login-button')

        username.send_keys('invalid_username')
        password.send_keys('invalid_password')
        login_button.click()

        # 断言错误消息存在
        error_message = self.driver.find_element(By.CLASS_NAME, 'error-message')
        self.assertIn('用户名或密码错误', error_message.text)

if __name__ == '__main__':
    unittest.main()
3. 常用断言方法
断言方法 作用
assertEqual(a, b) 验证 a == b
assertNotEqual(a, b) 验证 a != b
assertTrue(x) 验证 x 为 True
assertFalse(x) 验证 x 为 False
assertIn(a, b) 验证 a 在 b 中
assertNotIn(a, b) 验证 a 不在 b 中
assertIsNone(x) 验证 x 为 None
assertIsNotNone(x) 验证 x 不为 None

二、pytest 框架

pytest 是第三方测试框架,功能更强大,插件丰富,语法更简洁,是目前最流行的 Python 测试框架。

1. 安装

pip install pytest

2. 基本概念
  • 测试函数 :以 test_ 开头的普通函数
  • 测试类 :以 Test 开头的类,其中的方法以 test_ 开头
  • fixture:用于测试环境的初始化和清理
  • 参数化测试:一次编写,多次执行不同参数的测试
3. 简单示例

下面是使用 pytestfixture 实现的登录测试:

python 复制代码
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By

@pytest.fixture
def browser():
    # 初始化浏览器
    driver = webdriver.Firefox()
    driver.implicitly_wait(10)
    yield driver  # 返回driver给测试函数
    # 测试结束后关闭浏览器
    driver.quit()

def test_successful_login(browser):
    browser.get('https://example.com/login')
    
    username = browser.find_element(By.ID, 'username')
    password = browser.find_element(By.ID, 'password')
    login_button = browser.find_element(By.ID, 'login-button')

    username.send_keys('valid_username')
    password.send_keys('valid_password')
    login_button.click()

    welcome_message = browser.find_element(By.CLASS_NAME, 'welcome-message')
    assert '欢迎' in welcome_message.text

def test_failed_login(browser):
    browser.get('https://example.com/login')
    
    username = browser.find_element(By.ID, 'username')
    password = browser.find_element(By.ID, 'password')
    login_button = browser.find_element(By.ID, 'login-button')

    username.send_keys('invalid_username')
    password.send_keys('invalid_password')
    login_button.click()

    error_message = browser.find_element(By.CLASS_NAME, 'error-message')
    assert '用户名或密码错误' in error_message.text
4. 参数化测试

pytest 最强大的功能之一是参数化测试,可以使用 @pytest.mark.parametrize 装饰器:

python 复制代码
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By

@pytest.fixture
def browser():
    driver = webdriver.Firefox()
    yield driver
    driver.quit()

@pytest.mark.parametrize(
    "username, password, expected_message",
    [
        ("valid_user1", "valid_pass1", "欢迎"),  # 测试用例1
        ("valid_user2", "valid_pass2", "欢迎"),  # 测试用例2
        ("invalid_user", "wrong_password", "用户名或密码错误"),  # 测试用例3
    ]
)
def test_login_parameterized(browser, username, password, expected_message):
    browser.get('https://example.com/login')
    
    username_field = browser.find_element(By.ID, 'username')
    password_field = browser.find_element(By.ID, 'password')
    login_button = browser.find_element(By.ID, 'login-button')

    username_field.send_keys(username)
    password_field.send_keys(password)
    login_button.click()

    if "valid" in username:
        message = browser.find_element(By.CLASS_NAME, 'welcome-message').text
    else:
        message = browser.find_element(By.CLASS_NAME, 'error-message').text
    
    assert expected_message in message
5. 运行测试

在终端中执行测试:

python 复制代码
# 运行当前目录下所有以test_开头的文件
pytest

# 运行指定文件
pytest test_login.py

# 显示详细输出
pytest -v

# 生成HTML测试报告
pytest --html=report.html

三、unittest vs pytest 对比

特性 unittest pytest
断言方式 内置断言方法 使用 Python 原生 assert 语句
测试发现 基于类和方法命名规则 更灵活,支持更多命名模式
参数化测试 需要使用第三方库 内置参数化功能
测试夹具 setUp/tearDown 方法 灵活的 fixture 机制
插件生态 较少 丰富的插件(如测试报告、并行执行)
代码简洁度 较繁琐 简洁易读

四、推荐实践

  1. 使用 pytest :对于大多数项目,推荐使用 pytest,它的灵活性和丰富插件能大大提高效率
  2. 合理使用 fixture:将浏览器初始化、登录等操作封装到 fixture 中,避免代码重复
  3. 参数化测试:使用参数化覆盖多种测试场景,减少代码量
  4. 生成测试报告 :使用 pytest-htmlallure-pytest 生成美观的测试报告
相关推荐
程序员小远1 小时前
性能测试之性能调优
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·性能测试
Chengbei112 小时前
SoloXSS:一款现代化的自托管 XSS平台
人工智能·安全·web安全·网络安全·自动化·xss·安全架构
HAPPY酷2 小时前
【ROS2】16G 内存笔记本跑 ROS2 仿真?VMware 虚拟机“保姆级”配置指南 (R9 7940HX + RTX 4060)
java·linux·ide·windows·pycharm
xy345311 小时前
Wireshark捕获过滤器——语法元素详解
网络·测试工具·渗透测试·wireshark
BJHHZX199113 小时前
北京华恒智信为制造行业破解自动化伪升级难题,落地人机协作三阶段减编增效方案
自动化·绩效考核·人力资源管理·人机协作·员工激励
程序员吕洞宾16 小时前
开源多维表格SmartTable V1.6:自动化工作流,把重复操作交给系统即可
开源·自动化·github·多维表格·飞书多维表
2301_7803039016 小时前
网络安全、自动化运维、ERP、CRM、MES
运维·web安全·网络安全·自动化·安全威胁分析
csg110716 小时前
电路板抗干扰:电容、电感和弧线布线的应用
单片机·嵌入式硬件·物联网·自动化
环境栈笔记17 小时前
多账号浏览器选型检查清单:Profile、权限、Session 和任务日志怎么评估
前端·人工智能·后端·自动化
jieyucx18 小时前
Shell实战:无限循环监控Nginx服务,异常自动重启+双份日志留存
linux·运维·nginx·自动化·shell