How to write a custom `.assertFoo()` method in Python?

Question:

I’m writing some test cases for my application using Python’s unittest. Now I need to compare a list of objects with a list of another objects to check if the objects from the first list are what I’m expecting.

How can I write a custom .assertFoo() method? What should it do? Should it raise an exception on failure? If yes, which exception? And how to pass the error message? Should the error message be a unicode string or a bytestring?

Unfortunately, the official documentation doesn’t explain how to write custom assertion methods.

If you need a real-world example for this, continue reading.


The code I’m writing is somewhat like this:

def assert_object_list(self, objs, expected):
    for index, (item, values) in enumerate(zip(objs, expected)):
        self.assertEqual(
            item.foo, values[0],
            'Item {0}: {1} != {2}'.format(index, item.foo, values[0])
        )
        self.assertEqual(
            item.bar, values[1],
            'Item {0}: {1} != {2}'.format(index, item.bar, values[1])
        )

def test_foobar(self):
    objs = [...]  # Some processing here
    expected = [
        # Expected values for ".foo" and ".bar" for each object
        (1, 'something'),
        (2, 'nothing'),
    ]
    self.assert_object_list(objs, expected)

This approach makes it extremely easy to describe the expected values of each object in a very compact way, and without needing to actually create full objects.

However… When one object fails the assertion, no further objects are compared, and this makes debugging a bit more difficult. I would like to write a custom method that would unconditionally compare all objects, and then would display all objects that failed, instead of just the first one.

Asked By: Denilson Sá Maia

||

Answers:

You should create your own TestCase class, derived from unittest.TestCase. Then put your custom assert method into that test case class. If your test fails, raise an AssertionError. Your message should be a string. If you want to test all objects in the list rather than stop on a failure, then collect a list of failing indexes, and after the loop over all the objects, build an assert message that summarizes your findings.

Answered By: Ned Batchelder

I use the multiple inheritance in these cases. For example:

First. I define a class with methods that will incorporate.

import os

class CustomAssertions:
    def assertFileExists(self, path):
        if not os.path.lexists(path):
            raise AssertionError('File not exists in path "' + path + '".')

Now I define a class that inherits from unittest.TestCase and CustomAssertion

import unittest

class MyTest(unittest.TestCase, CustomAssertions):
    def test_file_exists(self):
        self.assertFileExists('any/file/path')

if __name__ == '__main__':
    unittest.main()
Answered By: Alan Cristhian

Just an example to sum up with a numpy comparaison unittest

import numpy as np
class CustomTestCase(unittest.TestCase):
    def npAssertAlmostEqual(self, first, second, rtol=1e-06, atol=1e-08):
        np.testing.assert_allclose(first, second, rtol=rtol, atol=atol)


class TestVector(CustomTestCase):
    def testFunction(self):
        vx = np.random.rand(size)
        vy = np.random.rand(size)
        self.npAssertAlmostEqual(vx, vy)
Answered By: parisjohn
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.