在 Python 面向对象编程中,类是代码组织的核心单元。对类的测试通常分为模块化测试(单元测试) 和集成测试,二者相辅相成,共同保障代码质量。

一、核心概念区分

  • 模块化测试(单元测试):针对单个类或类的独立方法进行测试,验证其在隔离环境下是否符合设计预期(如输入输出、异常处理等)。
  • 集成测试:测试多个类之间的交互逻辑,验证它们协作时是否能正确完成复杂功能(如依赖关系、数据传递等)。

二、模块化测试(单元测试)实践

Python 中常用unittest(内置)或pytest框架进行单元测试。核心原则是:隔离被测试对象,仅关注其自身逻辑

示例:定义待测试的类

假设我们有一个Order类(订单),包含计算总价、添加商品等方法:

python

运行

# order.py
class Product:
    """商品类,包含名称和单价"""
    def __init__(self, name: str, price: float):
        if price < 0:
            raise ValueError("商品价格不能为负数")
        self.name = name
        self.price = price

class Order:
    """订单类,包含添加商品、计算总价等功能"""
    def __init__(self):
        self.products = []  # 存储商品列表
    
    def add_product(self, product: Product, quantity: int = 1):
        """添加商品到订单,quantity为数量(默认为1)"""
        if quantity <= 0:
            raise ValueError("数量必须为正数")
        self.products.append((product, quantity))
    
    def calculate_total(self) -> float:
        """计算订单总价"""
        return sum(product.price * quantity for product, quantity in self.products)
单元测试实现(使用unittest

ProductOrder分别编写单元测试,重点测试:

  • 正常输入的处理结果
  • 异常输入的错误抛出
  • 边界情况(如数量为 1、价格为 0 等)

python

运行

# test_order_unit.py
import unittest
from order import Product, Order

class TestProduct(unittest.TestCase):
    """测试Product类的单元测试"""
    
    def test_product_normal_price(self):
        """测试正常价格的商品创建"""
        p = Product("苹果", 5.99)
        self.assertEqual(p.name, "苹果")
        self.assertEqual(p.price, 5.99)
    
    def test_product_negative_price(self):
        """测试价格为负数时是否抛出异常"""
        with self.assertRaises(ValueError) as ctx:
            Product("香蕉", -3.5)
        self.assertEqual(str(ctx.exception), "商品价格不能为负数")

class TestOrder(unittest.TestCase):
    """测试Order类的单元测试"""
    
    def setUp(self):
        """每个测试方法执行前初始化一个空订单"""
        self.order = Order()
        self.apple = Product("苹果", 5.99)
        self.banana = Product("香蕉", 3.5)
    
    def test_add_single_product(self):
        """测试添加单个商品"""
        self.order.add_product(self.apple, 2)
        self.assertEqual(len(self.order.products), 1)
        self.assertEqual(self.order.products[0], (self.apple, 2))
    
    def test_add_invalid_quantity(self):
        """测试添加数量为负数时是否抛出异常"""
        with self.assertRaises(ValueError) as ctx:
            self.order.add_product(self.banana, -1)
        self.assertEqual(str(ctx.exception), "数量必须为正数")
    
    def test_calculate_total(self):
        """测试计算总价的正确性"""
        self.order.add_product(self.apple, 2)  # 2*5.99=11.98
        self.order.add_product(self.banana, 3)  # 3*3.5=10.5
        self.assertAlmostEqual(self.order.calculate_total(), 22.48)

if __name__ == "__main__":
    unittest.main()
单元测试关键技巧
  1. 隔离性:通过setUp()初始化测试环境,每个测试方法独立运行,互不干扰。
  2. Mock 依赖:若类依赖外部资源(如数据库),使用unittest.mock模拟依赖,避免真实调用(例如模拟支付接口返回值)。
  3. 覆盖场景:不仅测试正常流程,还要覆盖异常、边界值(如空订单计算总价)等场景。

三、集成测试实践

当多个类协作完成功能时,需通过集成测试验证它们的交互是否正确。例如,订单完成后需要通过PaymentProcessor类处理支付,此时需测试OrderPaymentProcessor的协作。

示例:添加依赖类并编写集成测试

python

运行

# payment.py
class PaymentProcessor:
    """支付处理器,处理订单支付"""
    def process_payment(self, order: Order, amount: float) -> bool:
        """处理支付:若支付金额等于订单总价,返回True(支付成功),否则返回False"""
        if amount < 0:
            raise ValueError("支付金额不能为负数")
        return amount == order.calculate_total()
集成测试实现

测试OrderPaymentProcessor的协作逻辑:

python

运行

# test_integration.py
import unittest
from order import Order, Product
from payment import PaymentProcessor

class TestOrderPaymentIntegration(unittest.TestCase):
    """测试Order与PaymentProcessor的集成逻辑"""
    
    def setUp(self):
        self.order = Order()
        self.processor = PaymentProcessor()
        self.apple = Product("苹果", 5.0)
        self.order.add_product(self.apple, 2)  # 总价10.0
    
    def test_successful_payment(self):
        """测试支付金额等于总价时,支付成功"""
        result = self.processor.process_payment(self.order, 10.0)
        self.assertTrue(result)
    
    def test_insufficient_payment(self):
        """测试支付金额不足时,支付失败"""
        result = self.processor.process_payment(self.order, 8.0)
        self.assertFalse(result)
    
    def test_payment_with_negative_amount(self):
        """测试支付金额为负数时,是否抛出异常"""
        with self.assertRaises(ValueError) as ctx:
            self.processor.process_payment(self.order, -5.0)
        self.assertEqual(str(ctx.exception), "支付金额不能为负数")

if __name__ == "__main__":
    unittest.main()
集成测试关键原则
  1. 关注交互:不纠结单个类的内部逻辑,重点验证类之间的数据传递、接口调用是否符合预期。
  2. 逐步集成:从两个类的简单交互开始,逐步增加参与协作的类(如加入Discount类后,测试订单、支付、折扣的联动)。
  3. 模拟第三方:对外部系统(如真实支付接口)仍需用mock,避免测试依赖外部环境。

四、总结

测试类型 目标 工具示例 核心原则
模块化测试 验证单个类 / 方法的独立功能 unittest 隔离性、覆盖完整场景
集成测试 验证多个类的协作逻辑 unittest 关注交互、逐步集成

在实际开发中,应先通过单元测试保证每个类的正确性,再通过集成测试验证类之间的协作,二者结合可显著降低代码缺陷率。

更多推荐