Python: Using Doctests for Classes

Python: using doctests for classes

You're missing the code to actually run the doctests at the bottom of the file:

class Test:
<snip>

if __name__ == "__main__":
import doctest
doctest.testmod()

As for where to put the tests:

  • If it's testing the class as a whole, I'd put them in the class' docstring.
  • If it's testing the constructor, I'd put them in the constructor's docstring.
  • If it's testing a method (as it seems to be in this case), I'd actually put it them in that method's docstring.

doctest doesn't test classes methods in a module

I found out why.

Why it doesn't work

doctest tries to detect which tests don't belong to the tested module, and doesn't run them. This prevents running all the tests of your dependencies.

Here, my doctest belongs to simplemod.A while I am testing simplemod.

Recommended solution

From the doctest documentation about testing complex packages.

Rename A.py to a.py, and replace __init__.py, with

from . import a

def load_tests(loader, tests, ignore):
import unittest
import doctest
tests.addTests(doctest.DocTestSuite(a))
return tests

You can then run your test with a simple

$ python -m unittest

in the parent folder.

Using doctest on class property with py.test

Finally I found that the test doesn't pass only when I do right click/Run 'Doctest attribute_squared' in Pycharm.
When running pytest, the test passes.

Python: How can I define a class in a doctest?

Try it out in the interpreter; it uses ... to show continuation lines. >>> is only for a new statement or expression, while a class in incomplete until you've had an empty ... continuation line:

    >>> class A(MyClass):
... def __init__(self):
... super(A, self).__init__()
...

Executing Python doctest code

The difference is that when you execute via doctest, it is the __main__ module compared to executing directly where your script's if __name__ == '__main__' block will execute.

I don't know of a good solution other than to put all the information you need in the docstring itself:

def multiply_by_2(self):
"""
>>> t = Test(2)
>>> t.multiply_by_2()
4
"""
return self._number * 2

This will have the added benefit that users who are reading your docstrings will know what's going on ... They won't have to stumble upon your extraglobs keyword to figure out what t is and how it was initialized.

Suppressing doctest in abstract or Protocol classes

Your doc test has to do the same thing a user would be expected to do: define a subclass that implements do_something and instantiate that class.

class MyABC(ABC):
"""My docstring.

Here is a recommended use case for this item:

Examples:
>>> class Foo(MyABC):
... def do_something(self):
... return 'some expected behaviour'
...
>>> a = Foo()
>>> a.do_something()
'some expected behaviour'
"""

@abstractmethod
def do_something(self):
pass


Related Topics



Leave a reply



Submit