You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中如何针对不同被测对象复用测试用例?

问题描述

我有同一功能的多个实现,希望复用测试用例,和常见的Python单元测试基类子类场景不同的是,待复用的测试会执行由子类设置的不同被测对象(subjects-under-test)。我写了如下代码,但运行后没有执行任何测试,尝试自定义TestBase.__init__(包括用**kwargs)也没用,请问该如何对TestBase进行参数化?

原代码:

class TestBase(unittest.TestCase):
    def __init__(self, sut: Callable[[int], int]):
        super().__init__()

        self.sut = sut

    def test_1(self):
        expected = 1

        n = 1

        actual = self.sut(n)

        self.assertEqual(expected, actual)

    def test_2(self):
        expected = 2

        n = 2

        actual = self.sut(n)

        self.assertEqual(expected, actual)


class TestImplA(TestBase):
    def setUp(self):
        super().sut = impl_a


class TestImplB(TestBase):
    def setUp(self):
        super().sut = impl_b
解决方案

问题核心是你重写了TestBase的__init__方法,但unittest.TestCase的构造函数签名有固定要求,自定义参数会导致测试运行器无法正确实例化测试类,同时子类的setUp写法也不符合规范。以下是几种可行的解决方法:

方法一:通过类属性传递被测对象(最简洁)

修改基类,去掉自定义的__init__,改用类属性让子类指定被测对象,再在setUp中完成初始化:

import unittest
from typing import Callable

# 模拟被测实现
def impl_a(n: int) -> int:
    return n

def impl_b(n: int) -> int:
    return n

class TestBase(unittest.TestCase):
    sut: Callable[[int], int] = None  # 基类定义占位属性

    def setUp(self):
        if self.sut is None:
            raise NotImplementedError("子类必须设置sut属性")

    def test_1(self):
        self.assertEqual(self.sut(1), 1)

    def test_2(self):
        self.assertEqual(self.sut(2), 2)

class TestImplA(TestBase):
    sut = impl_a

class TestImplB(TestBase):
    sut = impl_b

if __name__ == "__main__":
    unittest.main()

这种方式不需要额外依赖,子类只需一行代码指定被测对象,测试运行器能正常识别并执行所有测试方法。

方法二:使用参数化测试(适合多实现批量验证)

如果不想创建多个子类,可以用unittest自带的subTest上下文管理器,或者第三方库parameterized来批量测试所有实现:

标准库实现

import unittest
from typing import Callable

def impl_a(n: int) -> int:
    return n

def impl_b(n: int) -> int:
    return n

class TestAllImpls(unittest.TestCase):
    def test_all_implementations(self):
        # 定义所有要测试的实现
        implementations = [("ImplA", impl_a), ("ImplB", impl_b)]
        for name, sut in implementations:
            with self.subTest(implementation=name):
                self.assertEqual(sut(1), 1)
                self.assertEqual(sut(2), 2)

if __name__ == "__main__":
    unittest.main()

第三方库parameterized实现

先通过pip install parameterized安装依赖,再编写代码:

import unittest
from parameterized import parameterized
from typing import Callable

def impl_a(n: int) -> int:
    return n

def impl_b(n: int) -> int:
    return n

class TestAllImpls(unittest.TestCase):
    @parameterized.expand([
        ("ImplA", impl_a),
        ("ImplB", impl_b),
    ])
    def test_implementations(self, name, sut):
        self.assertEqual(sut(1), 1)
        self.assertEqual(sut(2), 2)

if __name__ == "__main__":
    unittest.main()

方法三:动态生成测试类(保留基类子类结构)

如果坚持要使用基类子类的结构,也可以通过动态生成测试类的方式,避免手动编写重复的子类代码:

import unittest
from typing import Callable

def impl_a(n: int) -> int:
    return n

def impl_b(n: int) -> int:
    return n

def create_test_class(sut: Callable[[int], int], class_name: str) -> type:
    class TestImpl(TestBase):
        def setUp(self):
            self.sut = sut

    TestImpl.__name__ = class_name
    return TestImpl

class TestBase(unittest.TestCase):
    sut: Callable[[int], int] = None

    def test_1(self):
        self.assertEqual(self.sut(1), 1)

    def test_2(self):
        self.assertEqual(self.sut(2), 2)

# 动态生成测试类
TestImplA = create_test_class(impl_a, "TestImplA")
TestImplB = create_test_class(impl_b, "TestImplB")

if __name__ == "__main__":
    unittest.main()

内容的提问来源于stack exchange,提问作者Noel Yap

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 22:47:05