本文介绍了Python 中最常用的两个测试框架:unittest
和 pytest
,帮助你编写更规范、可维护的自动化测试用例。
unittest
是 Python 内置的标准库,无需额外安装,适合初学者入门。它借鉴了 JUnit 的设计理念,提供了测试用例、测试套件、断言等基本功能。
test_
开头下面是一个使用 unittest
测试登录功能的示例:
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()
断言方法 | 作用 |
---|---|
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
是第三方测试框架,功能更强大,插件丰富,语法更简洁,是目前最流行的 Python 测试框架。
pip install pytest
test_
开头的普通函数Test
开头的类,其中的方法以 test_
开头下面是使用 pytest
和 fixture
实现的登录测试:
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
pytest
最强大的功能之一是参数化测试,可以使用 @pytest.mark.parametrize
装饰器:
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
在终端中执行测试:
# 运行当前目录下所有以test_开头的文件
pytest
# 运行指定文件
pytest test_login.py
# 显示详细输出
pytest -v
# 生成HTML测试报告
pytest --html=report.html
特性 | unittest | pytest |
---|---|---|
断言方式 | 内置断言方法 | 使用 Python 原生 assert 语句 |
测试发现 | 基于类和方法命名规则 | 更灵活,支持更多命名模式 |
参数化测试 | 需要使用第三方库 | 内置参数化功能 |
测试夹具 | setUp/tearDown 方法 | 灵活的 fixture 机制 |
插件生态 | 较少 | 丰富的插件(如测试报告、并行执行) |
代码简洁度 | 较繁琐 | 简洁易读 |
pytest
,它的灵活性和丰富插件能大大提高效率pytest-html
或 allure-pytest
生成美观的测试报告