Python 自动化测试高级应用指南

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. 最佳实践

  1. 测试覆盖率:使用 coverage 工具测量测试覆盖率,确保代码被充分测试。
  2. 测试命名:为测试方法和测试文件使用清晰、描述性的名称。
  3. 测试隔离:确保测试之间相互独立,避免测试依赖。
  4. 测试夹具:使用测试夹具(fixtures)来设置和清理测试环境。
  5. 参数化测试:使用参数化测试来测试多种场景。
  6. 测试标记:使用测试标记来组织和运行特定的测试。
  7. 异常测试:测试函数是否正确处理异常情况。
  8. 性能测试:对于性能敏感的代码,编写性能测试。

6. 总结

Python 的自动化测试框架提供了丰富的功能,从基本的单元测试到复杂的集成测试和 Web 测试。通过掌握这些高级应用,我们可以编写更加可靠、高质量的代码。

在实际应用中,自动化测试可以用于单元测试、集成测试、Web 测试和数据库测试等多种场景,确保代码的正确性和可靠性。

希望本文对你理解和应用 Python 自动化测试有所帮助!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值