Python 自动化测试高级应用指南
1. 自动化测试基础
Python 的自动化测试主要通过 unittest 和 pytest 等框架实现。
# unittest 基础
import unittest
class TestMath(unittest.TestCase):
def test_add(self):
self.assertEqual(1 + 1, 2)
def test_subtract(self):
self.assertEqual(5 - 3, 2)
if __name__ == '__main__':
unittest.main()
2. unittest 高级应用
2.1 测试夹具
import unittest
class TestMath(unittest.TestCase):
def setUp(self):
# 测试前的准备工作
self.numbers = [1, 2, 3, 4, 5]
def tearDown(self):
# 测试后的清理工作
self.numbers = None
def test_sum(self):
self.assertEqual(sum(self.numbers), 15)
def test_average(self):
self.assertEqual(sum(self.numbers) / len(self.numbers), 3.0)
if __name__ == '__main__':
unittest.main()
2.2 测试套件
import unittest
class TestMath(unittest.TestCase):
def test_add(self):
self.assertEqual(1 + 1, 2)
def test_subtract(self):
self.assertEqual(5 - 3, 2)
class TestString(unittest.TestCase):
def test_length(self):
self.assertEqual(len("hello"), 5)
def test_upper(self):
self.assertEqual("hello".upper(), "HELLO")
# 创建测试套件
suite = unittest.TestSuite()
suite.addTest(TestMath('test_add'))
suite.addTest(TestMath('test_subtract'))
suite.addTest(TestString('test_length'))
suite.addTest(TestString('test_upper'))
# 运行测试套件
if __name__ == '__main__':
runner = unittest.TextTestRunner()
runner.run(suite)
2.3 断言方法
import unittest
class TestAssertions(unittest.TestCase):
def test_equal(self):
self.assertEqual(1 + 1, 2)
def test_not_equal(self):
self.assertNotEqual(1 + 1, 3)
def test_true(self):
self.assertTrue(1 + 1 == 2)
def test_false(self):
self.assertFalse(1 + 1 == 3)
def test_is_none(self):
self.assertIsNone(None)
def test_is_not_none(self):
self.assertIsNotNone("hello")
def test_in(self):
self.assertIn(1, [1, 2, 3])
def test_not_in(self):
self.assertNotIn(4, [1, 2, 3])
if __name__ == '__main__':
unittest.main()
3. pytest 高级应用
3.1 基本测试
# test_math.py
def test_add():
assert 1 + 1 == 2
def test_subtract():
assert 5 - 3 == 2
# 运行测试
# pytest test_math.py -v
3.2 测试夹具
import pytest
@pytest.fixture
def numbers():
return [1, 2, 3, 4, 5]
def test_sum(numbers):
assert sum(numbers) == 15
def test_average(numbers):
assert sum(numbers) / len(numbers) == 3.0
# 运行测试
# pytest test_math.py -v
3.3 参数化测试
import pytest
@pytest.mark.parametrize("a, b, expected", [
(1, 1, 2),
(2, 3, 5),
(5, 5, 10)
])
def test_add(a, b, expected):
assert a + b == expected
@pytest.mark.parametrize("a, b, expected", [
(5, 3, 2),
(10, 4, 6),
(7, 2, 5)
])
def test_subtract(a, b, expected):
assert a - b == expected
# 运行测试
# pytest test_math.py -v
3.4 测试标记
import pytest
@pytest.mark.slow
def test_slow_operation():
# 模拟慢操作
import time
time.sleep(2)
assert 1 + 1 == 2
@pytest.mark.skip(reason="暂时跳过")
def test_skip():
assert 1 + 1 == 2
@pytest.mark.xfail(reason="预期失败")
def test_xfail():
assert 1 + 1 == 3
# 运行测试
# pytest test_math.py -v
# pytest test_math.py -v -m "not slow"
4. 实际应用场景
4.1 单元测试
# math.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b
# test_math.py
import pytest
from math import add, subtract, multiply, divide
def test_add():
assert add(1, 2) == 3
assert add(-1, 1) == 0
assert add(0, 0) == 0
def test_subtract():
assert subtract(5, 3) == 2
assert subtract(3, 5) == -2
assert subtract(0, 0) == 0
def test_multiply():
assert multiply(2, 3) == 6
assert multiply(-1, 1) == -1
assert multiply(0, 5) == 0
def test_divide():
assert divide(6, 3) == 2
assert divide(5, 2) == 2.5
with pytest.raises(ValueError):
divide(1, 0)
# 运行测试
# pytest test_math.py -v
4.2 集成测试
# app.py
class User:
def __init__(self, name, email):
self.name = name
self.email = email
class UserService:
def __init__(self):
self.users = []
def add_user(self, name, email):
user = User(name, email)
self.users.append(user)
return user
def get_user_by_email(self, email):
for user in self.users:
if user.email == email:
return user
return None
# test_integration.py
import pytest
from app import UserService
def test_user_service():
# 创建服务实例
service = UserService()
# 添加用户
user = service.add_user("Alice", "alice@example.com")
assert user.name == "Alice"
assert user.email == "alice@example.com"
# 根据邮箱获取用户
found_user = service.get_user_by_email("alice@example.com")
assert found_user is not None
assert found_user.name == "Alice"
# 获取不存在的用户
not_found_user = service.get_user_by_email("bob@example.com")
assert not_found_user is None
# 运行测试
# pytest test_integration.py -v
4.3 Web 测试
# test_web.py
import pytest
from flask import Flask
from flask.testing import FlaskClient
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
@app.route('/users/<int:user_id>')
def get_user(user_id):
return f'User {user_id}'
@pytest.fixture
def client():
app.config['TESTING'] = True
with app.test_client() as client:
yield client
def test_hello(client: FlaskClient):
response = client.get('/')
assert response.status_code == 200
assert response.data == b'Hello, World!'
def test_get_user(client: FlaskClient):
response = client.get('/users/1')
assert response.status_code == 200
assert response.data == b'User 1'
# 运行测试
# pytest test_web.py -v
4.4 数据库测试
# test_database.py
import pytest
import sqlite3
@pytest.fixture
def db():
# 创建内存数据库
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
# 创建表
cursor.execute('''
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT,
email TEXT
)
''')
conn.commit()
yield conn
# 清理
conn.close()
def test_insert_user(db):
cursor = db.cursor()
# 插入用户
cursor.execute('INSERT INTO users (name, email) VALUES (?, ?)', ('Alice', 'alice@example.com'))
db.commit()
# 验证插入
cursor.execute('SELECT * FROM users WHERE email = ?', ('alice@example.com',))
user = cursor.fetchone()
assert user is not None
assert user[1] == 'Alice'
assert user[2] == 'alice@example.com'
def test_update_user(db):
cursor = db.cursor()
# 插入用户
cursor.execute('INSERT INTO users (name, email) VALUES (?, ?)', ('Alice', 'alice@example.com'))
db.commit()
# 更新用户
cursor.execute('UPDATE users SET name = ? WHERE email = ?', ('Alice Smith', 'alice@example.com'))
db.commit()
# 验证更新
cursor.execute('SELECT * FROM users WHERE email = ?', ('alice@example.com',))
user = cursor.fetchone()
assert user[1] == 'Alice Smith'
def test_delete_user(db):
cursor = db.cursor()
# 插入用户
cursor.execute('INSERT INTO users (name, email) VALUES (?, ?)', ('Alice', 'alice@example.com'))
db.commit()
# 删除用户
cursor.execute('DELETE FROM users WHERE email = ?', ('alice@example.com',))
db.commit()
# 验证删除
cursor.execute('SELECT * FROM users WHERE email = ?', ('alice@example.com',))
user = cursor.fetchone()
assert user is None
# 运行测试
# pytest test_database.py -v
5. 最佳实践
- 测试覆盖率:使用 coverage 工具测量测试覆盖率,确保代码被充分测试。
- 测试命名:为测试方法和测试文件使用清晰、描述性的名称。
- 测试隔离:确保测试之间相互独立,避免测试依赖。
- 测试夹具:使用测试夹具(fixtures)来设置和清理测试环境。
- 参数化测试:使用参数化测试来测试多种场景。
- 测试标记:使用测试标记来组织和运行特定的测试。
- 异常测试:测试函数是否正确处理异常情况。
- 性能测试:对于性能敏感的代码,编写性能测试。
6. 总结
Python 的自动化测试框架提供了丰富的功能,从基本的单元测试到复杂的集成测试和 Web 测试。通过掌握这些高级应用,我们可以编写更加可靠、高质量的代码。
在实际应用中,自动化测试可以用于单元测试、集成测试、Web 测试和数据库测试等多种场景,确保代码的正确性和可靠性。
希望本文对你理解和应用 Python 自动化测试有所帮助!

1252

被折叠的 条评论
为什么被折叠?



