11

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)
Community
  • 1
  • 1
Felipe
  • 3,003
  • 2
  • 26
  • 44

1 Answers1

15

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]
'{}'
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • In the real code, `kwargs` gets built rather than simply passed-in, so I can't test with the single-key or empty dicts. `literal_eval` is a good tip, though. Thanks! – Felipe Sep 15 '15 at 00:24