alisianoi
alisianoi

Reputation: 2363

How to reuse the same tests to test different implementations?

My language is python 3 and I am trying to understand how to use the same set of tests to test different implementations of the same algorithm.

So far I am looking at the built-in unittest and my impression is that I have to make some sort of a class hierachy: a class that inherits from unittest.TestCase and implements all the actual tests and several descendants from its class that each test particular implementations with the tests from the parent.

However, this is just my idea of how it should look like. Could you please tell me how to actually use the same set of tests to test different functions that implement the same algorithm?

Upvotes: 6

Views: 2712

Answers (3)

Mykhaylo Kopytonenko
Mykhaylo Kopytonenko

Reputation: 953

Use parameterized tests with your tested functions as a parameter.

For example, using ddt module for parameterized testing:

def sum1(list1):
    return sum(list1)

def sum2(list1):
    res = 0
    for x in list1:
        res += x
    return res

import unittest
from ddt import ddt, data

@ddt
class SumTest(unittest.TestCase):

    @data(sum1, sum2)
    def test_sum(self, param):
        self.assertEqual(param([1, 2, 3]), 6)


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

In this example, you have two functions "sum1" and "sum2" implementing the same algorithm: summing of list elements. In your test class, you have only one testing method "test_sum" that takes the concrete summing function as a parameter. The two summing functions are specified as a list of values for a parameterized test.

You can install "ddt" with pip:

pip install ddt

Upvotes: 1

quamrana
quamrana

Reputation: 39354

I've done this by writing tests in a class that does not inherit from TestCase and then writing multiple test classes that do inherit from TestCase and the tests, but either have a factory method or a class attribute of the class to instantiate:

class TestAnyImplementation:
    def testThis(self):
        obj = getImpl()  # call to factory method
        self.assertTrue(obj.isEmpty())

class TestFooImplementation(TestAnyImplementation,TestCase):
    def getImpl(self):
        return Foo()

class TestBarImplementation(TestAnyImplementation,TestCase):
    def getImpl(self):
        return Bar()

Upvotes: 5

user1907906
user1907906

Reputation:

You can leave your tests unchaged if you import the different implementations with the same name. To test impl1, do

import impl1 as impl

in your test code. To test impl2, do

import impl2 as impl

Everything else can be left unchanged, if both impl1 and impl2 have the same interface.

Edit: You can wrap these import in an if clause and use a commandline parameter to select one.

chooseImpl = ... # get commandline parameter
if chooseImp == "impl1":
    import impl1 as impl
elif chooseImp == "impl2":
    import impl2 as impl

Using this approach you can don't have to change the test.

Upvotes: 1

Related Questions