如何在 python 中对不同的实现使用相同的单元测试?

How to use same unit test for different implementations in python?

我正在开发多个函数来回答同一个问题,但使用不同的算法。

所以所有函数的相同输入应该生成相同的输出,这就是为什么我想使用相同的单元测试而不是必须创建具有相同逻辑的多个测试。

我正在使用 Python 单元测试框架,我想使用 抽象测试 classfunction 变量定义通用测试,这样我就可以用我想在另一个正常测试 class 中测试的那个通用函数实例化。但似乎我无法在子 class.

中实例化 function 变量

这里是一个摘要示例 class,其中包含针对多个函数的通用测试。

class AbstractTestCase():

    def test_generic_input_one(self):
        result = self.function("input 1")
        self.assertFalse(result)

    def test_generic_input_two(self):
        result = self.function("input 2")
        self.assertTrue(result)

在这里,您将有一个针对 function_a 的特定测试 class,它继承了 AbstractTestCase class 的通用测试,并实现了自己的测试。

class TestsFunctionA(AbstractTestCase, unittest.TestCase):

    def setUp(self):
        self.function = function_a

    def test_specific_input(self):
        result = self.assertTrue(self.function("specific input"))
        self.assertTrue(result)

我很确定它可以完成,但我似乎找不到示例来了解如何实现它。我想避免代码重复。

最简单最好的方法是什么?

我一直在寻找它并找到了几个例子:

但对我帮助最大的是 vegard's answer 关于制作一个 class 工厂,它将接受参数并相应地创建 TestCase

The function takes the parameters of the parameterised test case and the actual TestCase class can refer to them without any problems.

这是一个例子,取一个 foo.py 文件:

import unittest

def make_test_case(x):
    class MyTestCase(unittest.TestCase):
        def test_foo(self):
            self.assertEquals(x, 1)

    return MyTestCase

class ConcreteTestCase(make_test_case(1)): 
    pass

然后 运行 测试:

python -m unittest -v foo

基本上这非常灵活并且非常适合我的用例。

基本上你需要参数化你用函数测试。

对于 unittest 你可以使用 ddt

@ddt
class ProblemTestCase(unittest.TestCase):
    def test_specific_input(self):
        self.assertTrue(function_a("specific input"))

    @data(function_a, function_b)
    def test_generic_input_one(self, function):
        result = function("input 1")
        self.assertFalse(result)

    @data(function_a, function_b)
    def test_generic_input_two(self, function):
        result = function("input 2")
        self.assertTrue(result)

或者,您可以只使用普通的 OOP:

class AbstractTestCase(object):

    def test_generic_input_one(self):
        result = self.function("input 1")
        self.assertFalse(result)

    def test_generic_input_two(self):
        result = self.function("input 2")
        self.assertTrue(result)

class TestsFunctionA(AbstractTestCase, unittest.TestCase):

    def function(self, param):
        return function_a(param)

    def test_specific_input(self):
        self.assertTrue(self.function("specific input"))

class TestsFunctionB(AbstractTestCase, unittest.TestCase):

    def function(self, param):
        return function_b(param)

    def test_another_specific_input(self):
        self.assertTrue(self.function("another specific input"))

我来这里是为了寻找一种方法来测试同一功能的多个实现。我的用例是测试学生提交的不同搜索算法,这些算法都提供相同的测试数据并且应该 return 相同的结果。

Sylhare 的答案很容易采纳,但分享也无妨,方法如下:

import unittest

def function_a():
    result = ...
    return result

def function_b():
    result = ...
    return result

def make_test(function):

    class TestImplementation(unittest.TestCase):

        def test_foo(self):
            self.assertEquals(function, 1)

    return TestImplementation

class TestImplementationA(make_test(function_a)): 
    pass

class TestImplementationB(make_test(function_b)): 
    pass

给定一个结构

├── README.md
├── requirements.txt
├── test
│   ├── __init__.py
│   └── two_sum
│       ├── __init__.py
│       ├── base_test_suite.py
│       ├── test_brute_force.py
│       └── test_two_pass_hash_table.py
└── two_sum
    ├── __init__.py
    ├── brute_force.py
    └── two_pass_hash_table.py

在[=14中对应的文件中有brute-force和two-pass hash-table解法(函数调用two_sum) =]模块。

base_test_suite.py

class TestTwoSum:
    def __init__(self, unittest, two_sum_func):
        self.two_sum = two_sum_func
        self.unittest = unittest

    def test_it_returns_indices_of_two_numbers_that_add_up_to_target(self):
        # given
        numbers = [2, 7, 11, 15]
        target = 9

        # when
        result = self.two_sum(numbers, target)

        # then
        self.unittest.assertEqual(result, [0, 1])

test_brute_force.py

from unittest import TestCase
from test.two_sum.base_test_suite import TestTwoSum
from two_sum.brute_force import two_sum


class Test(TestCase):
    def test(self):
        case = TestTwoSum(self, two_sum)
        case.test_it_returns_indices_of_two_numbers_that_add_up_to_target()

test_two_pass_hash_table.py

from unittest import TestCase
from test.two_sum.base_test_suite import TestTwoSum
from two_sum.two_pass_hash_table import two_sum


class Test(TestCase):
    def test(self):
        case = TestTwoSum(self, two_sum)
        case.test_it_returns_indices_of_two_numbers_that_add_up_to_target()

然后 可以 运行 python -m unittest 这将 运行 对两个和问题的不同解决方案进行相同的单元测试。