2

Let's say I have a web service ServA written in python and I want to write some unit tests.

ServA does several things (with different views) but all the views produce a similar log of the requests.

These tests should check the logs of ServA in the different circumstances, so there is a lot of repeated code for these unit tests (the structure of the logs is always the same).

My idea is to write a generic function to avoid repetition of code and I have found this other question that solves the problem creating a generic method inside the unittest class.

But now what if I have another web service ServB and another set of tests and I need to do the same?

Is there a way to reuse the generic function?

Should I simply create a test class with the method to check the logs like this:

class MyMetaTestClass(unittest.TestCase):
    def check_logs(self, log_list, **kwargs):
       #several self.assertEqual

and then the tests for ServA and ServB inherit this class like this:

class TestServA(MyMetaTestClass):
    def test_log1(self):
       logs = extract_the_logs()
       self.check_logs(logs, log_1=1, log2='foo')

is there another (better) way?

Community
  • 1
  • 1
Giovanni Di Milia
  • 13,480
  • 13
  • 55
  • 67

2 Answers2

10

You can inherit from a common base class like you did, but the base class doesn't have to be a TestCase subclass itself - you can just make it a mixin class:

# testutils.py
class LogCheckerMixin(object):
    """ this class adds log checking abilities to a TestCase.
    """  
    def check_logs(self, logs, **kw):
       self.assertWhatever(something)


# myserver/tests.py
import unittest
from testutils import LogCheckerMixin

class MyServerTest(unittest.TestCase, LogCheckerMixin):
    def test_log1(self):
        logs = extract_the_logs()
        self.check_logs(logs, log_1=1, log2='foo')

Or you can just make it a plain function and call it from your test:

# testutils.py
def check_logs(testcase, logs, **kw):
    testcase.assertWhatever(something)


# myserver/tests.py
import unittest
from testutils import check_logs

class MyServerTest(unittest.TestCase):
    def test_log1(self):
        logs = extract_the_logs()
        check_logs(self, logs, log_1=1, log2='foo')
bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
0

It's rather opinion based, but what I've seen most often is a set of separate helper classes, which can be used by any tests suite.

I usually create the infrastructure folder/namespace/module/package (in the test project) not confuse tests which should concern only domain aspects with technical issues. In this case you could have something like this:

logHelper.py:

def assert_something_about_logs(logs, something):
    # utility code
    # do an assertion

def assert_something_else(logs):
    # utility code
    # do an assertion

etc.

This way your unit tests will read well, for example assert_that_logs_contain(errorMessage="Something went wrong"), and all technicalities are hidden not to obscure the test.

BartoszKP
  • 34,786
  • 15
  • 102
  • 130