Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way of unit testing __repr__ with dict

Say I have a class given by:

class MyClass:
    def __init__(self, **kwargs):
        self.kwargs = kwargs
    def __repr__(self):
        return "<%s: %r>" % (self.__class__.__name__, self.kwargs)

__repr__ isn't really important for core functionality, but occasionally gets called for logging, shows up in stack traces, and such, so I'd like to unit-test it.

The problem is similar to that faced when using doctest, but I'd rather keep any complexity (like sorting) in the test function and not in __repr__.

Right now I'm using eval and re to extract the dictionary from the repr() call, but I wanted to check if there were non-eval alternatives out there that people used.

def test_repr():
    retval = repr(MyClass(a=1, b=2, c=3))
    match = re.match("^<MyClass: ({.*})>\Z", retval)
    assert match
    assert eval(match.group(1)) == dict(a=1, b=2, c=3)
like image 652
Felipe Avatar asked Sep 14 '15 16:09

Felipe


People also ask

What is the __ repr __ method used for?

According to the official documentation, __repr__ is used to compute the “official” string representation of an object and is typically used for debugging.

What is __ repr __ for in Python?

Python __repr__() function returns the object representation in string format. This method is called when repr() function is invoked on the object. If possible, the string returned should be a valid Python expression that can be used to reconstruct the object again.

What should repr return?

The repr() function returns the string representation of the value passed to eval function by default. For the custom class object, it returns a string enclosed in angle brackets that contains the name and address of the object by default.


1 Answers

You only need to check that the kwargs dictionary is correctly being represented in the output, so just pass zero or one keyword arguments:

>>> repr(MyClass(foo='bar')) == "<MyClass: {'foo': 'bar'}>"
True
>>> repr(MyClass()) == '<MyClass: {}>'
True

Then ordering doesn't matter at all.


If you decide to stick with evaluating the extracted dictionary, use ast.literal_eval instead of vanilla eval. I would also use a slice rather than re, as you know the expected format:

>>> '<MyClass: {}>'[10:-1]
'{}'
like image 159
jonrsharpe Avatar answered Oct 23 '22 05:10

jonrsharpe