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

时间:2018-01-12 22:06:58

标签: python unit-testing automated-tests tdd python-unittest

我正在开发多个功能,可以回答相同的问题但使用不同的算法。

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

我使用的是 Python unittest框架,我想使用抽象测试类来使用函数定义通用测试变量,以便我可以使用我想要在另一个普通测试类中测试的泛型函数来实例化该泛型函数。但似乎我无法在子类中实例化 function 变量。

所以这是一个示例抽象类,它包含多个函数的泛型测试。

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的特定测试类,它继承了AbstractTestCase类的通用测试,并实现了自己的测试。

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)

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

最简单,最好的方法应该是什么?

4 个答案:

答案 0 :(得分:4)

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

对于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"))

答案 1 :(得分:2)

我一直在寻找它并得到了一些例子:

但最让我帮助的是vegard's answer关于创建一个类工厂,它会接受参数并相应地创建TestCase

  

该函数采用参数化测试用例的参数,实际的TestCase类可以毫无问题地引用它们。

以下是一个示例,请使用{<1}}文件:

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

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

答案 2 :(得分:2)

给出一个结构

├── 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

并且two_sum模块的相应文件中有蛮力和两遍哈希表解决方案(称为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来为两个和问题的不同解决方案运行相同的单元测试。

答案 3 :(得分:0)

我是来这里寻找一种方法来测试同一功能的多个实现的。我的用例是测试学生提交的不同搜索算法的提交内容,这些提交内容都将获得相同的测试数据,并应返回相同的结果。

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