跳转至

Python进阶测试用例

测试目标: 验证Python高级特性和功能的正确性 测试类型: 单元测试、性能测试 涉及组件: 装饰器、生成器、上下文管理器、并发编程


📋 测试概述

测试目标

  1. 高级特性测试: 验证Python高级特性
  2. 并发测试: 验证并发和异步编程
  3. 性能测试: 评估代码执行效率
  4. 内存测试: 验证内存使用情况

测试环境

  • Python版本: 3.8+
  • 测试框架: pytest
  • 性能分析: cProfile, timeit

🧪 测试用例列表

1. 装饰器测试

测试用例1.1: 基础装饰器

测试目标: 验证装饰器功能

测试代码:

Python
import pytest
from functools import wraps
import time

def test_basic_decorator():
    """测试基础装饰器"""
    def my_decorator(func):
        @wraps(func)  # @wraps保留被装饰函数的元信息(名称、文档字符串等)
        def wrapper(*args, **kwargs):  # *args/**kwargs接收任意位置参数和关键字参数
            print("Before function call")
            result = func(*args, **kwargs)
            print("After function call")
            return result
        return wrapper

    @my_decorator
    def greet(name):
        return f"Hello, {name}!"

    result = greet("Alice")
    assert result == "Hello, Alice!"

    # 验证函数名和文档字符串
    assert greet.__name__ == "greet"

    print("✓ 基础装饰器测试通过")

预期结果: 装饰器正确执行,函数名保持不变


测试用例1.2: 带参数的装饰器

测试目标: 验证带参数的装饰器

测试代码:

Python
def test_decorator_with_args():
    """测试带参数的装饰器"""
    def repeat(times):
        def decorator(func):
            @wraps(func)
            def wrapper(*args, **kwargs):
                results = []
                for _ in range(times):
                    result = func(*args, **kwargs)
                    results.append(result)
                return results
            return wrapper
        return decorator

    @repeat(3)
    def greet(name):
        return f"Hello, {name}!"

    results = greet("Alice")
    assert results == ["Hello, Alice!", "Hello, Alice!", "Hello, Alice!"]

    print("✓ 带参数的装饰器测试通过")

预期结果: 函数执行指定次数


测试用例1.3: 类装饰器

测试目标: 验证类装饰器

测试代码:

Python
def test_class_decorator():
    """测试类装饰器"""
    def singleton(cls):
        instances = {}

        @wraps(cls)
        def get_instance(*args, **kwargs):
            if cls not in instances:
                instances[cls] = cls(*args, **kwargs)
            return instances[cls]

        return get_instance

    @singleton
    class MyClass:
        def __init__(self, value):
            self.value = value

    # 创建两个实例
    instance1 = MyClass(10)
    instance2 = MyClass(20)

    # 验证是同一个实例
    assert instance1 is instance2
    assert instance1.value == 10  # 第一个创建的值

    print("✓ 类装饰器测试通过")

预期结果: 类装饰器正确实现单例模式


2. 生成器测试

测试用例2.1: 基础生成器

测试目标: 验证生成器功能

测试代码:

Python
def test_basic_generator():
    """测试基础生成器"""
    def simple_generator():
        yield 1  # yield将函数变为生成器,惰性逐个产出值
        yield 2
        yield 3

    # 获取生成器
    gen = simple_generator()

    # 使用next获取值
    assert next(gen) == 1
    assert next(gen) == 2
    assert next(gen) == 3

    # 使用for循环
    gen = simple_generator()
    result = list(gen)
    assert result == [1, 2, 3]

    print("✓ 基础生成器测试通过")

预期结果: 生成器正确生成值


测试用例2.2: 生成器表达式

测试目标: 验证生成器表达式

测试代码:

Python
def test_generator_expression():
    """测试生成器表达式"""
    # 生成器表达式
    squares = (x**2 for x in range(5))

    # 验证是生成器
    assert hasattr(squares, '__iter__')  # hasattr()检查对象是否拥有指定属性
    assert hasattr(squares, '__next__')

    # 转换为列表
    result = list(squares)
    assert result == [0, 1, 4, 9, 16]

    # 带条件的生成器表达式
    even_squares = (x**2 for x in range(10) if x % 2 == 0)
    result = list(even_squares)
    assert result == [0, 4, 16, 36, 64]

    print("✓ 生成器表达式测试通过")

预期结果: 生成器表达式正确工作


测试用例2.3: yield from

测试目标: 验证yield from

测试代码:

Python
def test_yield_from():
    """测试yield from"""
    def sub_generator1():
        yield 1
        yield 2

    def sub_generator2():
        yield 3
        yield 4

    def main_generator():
        yield from sub_generator1()  # yield from委托给子生成器,简化嵌套yield
        yield from sub_generator2()
        yield 5

    result = list(main_generator())
    assert result == [1, 2, 3, 4, 5]

    print("✓ yield from测试通过")

预期结果: yield from正确委托给子生成器


3. 上下文管理器测试

测试用例3.1: 基础上下文管理器

测试目标: 验证上下文管理器

测试代码:

Python
def test_context_manager():
    """测试上下文管理器"""
    class MyContext:
        def __enter__(self):
            print("Entering context")
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            print("Exiting context")
            return False

    # 使用with语句
    with MyContext() as ctx:
        assert ctx is not None
        print("Inside context")

    print("✓ 基础上下文管理器测试通过")

预期结果: 上下文管理器正确进入和退出


测试用例3.2: contextlib装饰器

测试目标: 验证contextlib装饰器

测试代码:

Python
from contextlib import contextmanager

def test_contextlib_decorator():
    """测试contextlib装饰器"""
    @contextmanager  # @contextmanager用yield将普通函数变为上下文管理器
    def my_context():
        print("Entering context")
        try:
            yield "resource"
        finally:
            print("Cleaning up")

    # 使用with语句
    with my_context() as resource:
        assert resource == "resource"
        print("Using resource")

    print("✓ contextlib装饰器测试通过")

预期结果: contextlib装饰器正确工作


4. 并发编程测试

测试用例4.1: 多线程

测试目标: 验证多线程编程

测试代码:

Python
import threading

def test_multithreading():
    """测试多线程"""
    results = []

    def worker(value):
        results.append(value * 2)

    # 创建线程
    threads = []
    for i in range(5):
        t = threading.Thread(target=worker, args=(i,))  # threading.Thread创建新线程执行并发任务
        threads.append(t)
        t.start()

    # 等待所有线程完成
    for t in threads:
        t.join()

    # 验证结果
    assert len(results) == 5
    assert set(results) == {0, 2, 4, 6, 8}

    print("✓ 多线程测试通过")

预期结果: 多线程正确执行


测试用例4.2: 线程锁

测试目标: 验证线程锁

测试代码:

Python
def test_thread_lock():
    """测试线程锁"""
    counter = 0
    lock = threading.Lock()

    def increment():
        nonlocal counter  # nonlocal声明引用外层函数的变量(非全局)
        for _ in range(1000):
            with lock:
                counter += 1

    # 创建线程
    threads = []
    for _ in range(10):
        t = threading.Thread(target=increment)
        threads.append(t)
        t.start()

    # 等待所有线程完成
    for t in threads:
        t.join()

    # 验证结果
    assert counter == 10000

    print("✓ 线程锁测试通过")

预期结果: 线程锁正确保护共享资源


测试用例4.3: 异步编程

测试目标: 验证异步编程

测试代码:

Python
import asyncio

async def test_async_await():
    """测试async/await"""
    async def fetch_data(delay):  # async def定义协程函数,await暂停等待异步结果
        await asyncio.sleep(delay)
        return f"Data after {delay}s"

    # 创建协程
    coro1 = fetch_data(0.1)
    coro2 = fetch_data(0.2)

    # 并发执行
    results = await asyncio.gather(coro1, coro2)

    # 验证结果
    assert len(results) == 2
    assert "Data after 0.1s" in results[0]
    assert "Data after 0.2s" in results[1]

    print("✓ async/await测试通过")

def test_async_with_pytest():
    """在pytest中测试async函数"""
    asyncio.run(test_async_await())  # asyncio.run()启动异步事件循环并执行协程

预期结果: 异步函数正确执行


5. 性能测试

测试用例5.1: 列表推导vs循环

测试目标: 对比列表推导和循环的性能

测试代码:

Python
import timeit

def test_list_comprehension_performance():
    """测试列表推导性能"""
    # 列表推导
    list_comp_time = timeit.timeit(
        "[x**2 for x in range(1000)]",
        number=1000,
        globals=globals(),
    )

    # for循环
    for_loop_time = timeit.timeit(
        """
result = []
for x in range(1000):
    result.append(x**2)
""",
        number=1000,
        globals=globals(),
    )

    print(f"列表推导时间: {list_comp_time:.4f}s")
    print(f"for循环时间: {for_loop_time:.4f}s")

    # 列表推导应该更快
    assert list_comp_time < for_loop_time

    print("✓ 列表推导性能测试通过")

预期结果: 列表推导比for循环更快


测试用例5.2: 生成器vs列表

测试目标: 对比生成器和列表的内存使用

测试代码:

Python
import sys

def test_generator_memory():
    """测试生成器内存使用"""
    # 列表
    list_obj = [x**2 for x in range(1000000)]
    list_size = sys.getsizeof(list_obj)

    # 生成器
    gen_obj = (x**2 for x in range(1000000))
    gen_size = sys.getsizeof(gen_obj)

    print(f"列表大小: {list_size / 1024:.2f} KB")
    print(f"生成器大小: {gen_size / 1024:.2f} KB")

    # 生成器应该占用更少内存
    assert gen_size < list_size

    print("✓ 生成器内存测试通过")

预期结果: 生成器占用更少内存


6. 元编程测试

测试用例6.1: 元类

测试目标: 验证元类

测试代码:

Python
def test_metaclass():
    """测试元类"""
    class SingletonMeta(type):
        _instances = {}

        def __call__(cls, *args, **kwargs):  # __call__使实例可像函数一样被调用
            if cls not in cls._instances:
                cls._instances[cls] = super().__call__(*args, **kwargs)  # super()调用父类方法
            return cls._instances[cls]

    class MyClass(metaclass=SingletonMeta):
        def __init__(self, value):
            self.value = value

    # 创建两个实例
    instance1 = MyClass(10)
    instance2 = MyClass(20)

    # 验证是同一个实例
    assert instance1 is instance2
    assert instance1.value == 10

    print("✓ 元类测试通过")

预期结果: 元类正确实现单例模式


测试用例6.2: getattr__和__setattr

测试目标: 验证动态属性访问

测试代码:

Python
def test_dynamic_attributes():
    """测试动态属性访问"""
    class DynamicAttributes:
        def __init__(self):
            self._data = {}

        def __getattr__(self, name):
            if name.startswith('_'):
                raise AttributeError(name)
            return self._data.get(name, f"Default: {name}")

        def __setattr__(self, name, value):
            if name.startswith('_'):
                super().__setattr__(name, value)
            else:
                self._data[name] = value

    obj = DynamicAttributes()

    # 设置属性
    obj.name = "Alice"
    obj.age = 25

    # 获取属性
    assert obj.name == "Alice"
    assert obj.age == 25
    assert obj.city == "Default: city"

    # 访问不存在的私有属性(_data 存在于 __dict__ 中,不会触发 __getattr__)
    # __getattr__ 仅在常规属性查找失败时才被调用
    assert isinstance(obj._data, dict)  # _data 通过 super().__setattr__ 设置,可正常访问

    # 访问不存在的私有属性会触发 __getattr__,从而抛出 AttributeError
    try:
        _ = obj._nonexistent
        assert False, "Should raise AttributeError"
    except AttributeError:
        pass

    print("✓ 动态属性访问测试通过")

预期结果: 动态属性访问正确工作


📊 测试执行

运行所有测试

Bash
# 运行所有测试
pytest tests/test_python_advanced.py -v

# 运行特定测试
pytest tests/test_python_advanced.py::test_basic_decorator -v

# 生成覆盖率报告
pytest tests/test_python_advanced.py --cov=python_advanced --cov-report=html

✅ 验证方法

1. 自动化验证

  • 运行所有测试用例
  • 检查断言是否通过
  • 记录测试结果

2. 性能基准

  • 建立性能基准
  • 监控性能变化
  • 优化性能瓶颈

3. 内存分析

  • 使用memory_profiler分析内存
  • 检查内存泄漏
  • 优化内存使用

📝 测试报告

测试报告应包含:

  1. 测试概览
  2. 测试用例数量
  3. 通过/失败统计
  4. 代码覆盖率

  5. 详细结果

  6. 每个测试用例的结果
  7. 性能指标
  8. 内存使用情况

  9. 问题分析

  10. 失败原因分析
  11. 改进建议
  12. 后续计划

测试完成标准: 所有测试用例通过 推荐测试频率: 每次代码更新 测试维护周期: 每周