object reuse in python doctest

不问归期 提交于 2019-12-12 10:37:46

问题


I have a sample doctest like this one.

"""
This is the "iniFileGenerator" module.
>>> hintFile = "./tests/unit_test_files/hint.txt"
>>> f = iniFileGenerator(hintFile)
>>> print f.hintFilePath
./tests/unit_test_files/hint.txt
"""
class iniFileGenerator:
    def __init__(self, hintFilePath):
        self.hintFilePath = hintFilePath
    def hello(self):
        """
        >>> f.hello()
        hello
        """
        print "hello"
if __name__ == "__main__":
    import doctest
    doctest.testmod()

When I execute this code, I got this error.

Failed example:
    f.hello()
Exception raised:
    Traceback (most recent call last):
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/doctest.py", line 1254, in __run
        compileflags, 1) in test.globs
      File "<doctest __main__.iniFileGenerator.hello[0]>", line 1, in <module>
        f.hello()
    NameError: name 'f' is not defined

This error is caused by accessing 'f' which was not accessible when testing hello() method.

Is there any way to share the object which is created before? Without it, one need to create object all the time when it's necessary.

def hello(self):
    """
    hintFile = "./tests/unit_test_files/hint.txt"
    >>> f = iniFileGenerator(hintFile)
    >>> f.hello()
    hello
    """
    print "hello"

回答1:


You can use testmod(extraglobs={'f': initFileGenerator('')}) to define a reusable object globally.

As the doctest doc says,

extraglobs gives a dict merged into the globals used to execute examples. This works like dict.update()

But I used to test all methods in __doc__ of class before all methods.

class MyClass(object):
    """MyClass
    >>> m = MyClass()
    >>> m.hello()
    hello
    >>> m.world()
    world
    """

    def hello(self):
        """method hello"""
        print 'hello'

    def world(self):
        """method world"""
        print 'world'



回答2:


To obtain literate modules with tests that all use a shared execution context (i.e. individual tests that can share and re-use results), one has to look at the relevant part of documentation on the execution context, which says:

... each time doctest finds a docstring to test, it uses a shallow copy of M‘s globals, so that running tests doesn’t change the module’s real globals, and so that one test in M can’t leave behind crumbs that accidentally allow another test to work.

...

You can force use of your own dict as the execution context by passing globs=your_dict to testmod() or testfile() instead.

Given this, I managed to reverse-engineer from doctest module that besides using copies (i.e. the dict's copy() method), it also clears the globals dict (using clear()) after each test.

Thus, one can patch their own globals dictionary with something like:

class Context(dict):
    def clear(self):
        pass
    def copy(self):
        return self 

and then use it as:

import doctest
from importlib import import_module

module = import_module('some.module')
doctest.testmod(module,
                # Make a copy of globals so tests in this
                # module don't affect the tests in another
                glob=Context(module.__dict__.copy()))



回答3:


For anyone like me that finds this, here's an easy hack that solves this problem.

In your module documentation, attach the "global" values as a property of the builtins module, e.g.

"""
My module documentation

>>> import builtins
>>> builtins.sample_value = "Here is a long value"
>>> builtins.sample_func = lambda x: x.lower()
"""

The builtins module is automatically imported into every scope, and so its properties will be available in your functions, including doctest functions

def first_char_func(s: str) -> str:
   """
   Returns the first char of a function

   >>> first_char_func(sample_func(sample_value))
   h
   """  
   return s[0] if len(s) > 0 else None

Arguably however, once you've gotten to this stage, you're better off just writing a unit test.



来源:https://stackoverflow.com/questions/13106118/object-reuse-in-python-doctest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!