使用py.test为类属性编写doctest时遭遇NameError问题求助
我尝试用py.test通过doctest测试类的@property属性,但运行测试时出现了NameError,提示类未定义。以下是我的示例代码:
class ExampleClass: def __init__(self, attribute): self.attribute = attribute @property def attribute_squared(self): """ Examples: >>> ExampleClass(attribute=2).attribute_squared 4 """ return self.attribute ** 2
运行py.test后得到的错误信息:
Error **********************************************************************
Line 3, in ExampleClass
Failed example: ExampleClass(attribute=2)
Exception raised:
Traceback (most recent call last):
File "C:\Program Files\JetBrains\PyCharm Community Edition 2017.1.5\helpers\pycharm\docrunner.py", line 140, in __run
compileflags, 1), test.globs)
File "<doctest ExampleClass[0]>", line 1, in
ExampleClass(attribute=2).attribute_squared
NameError: name 'ExampleClass' is not defined
想请教下有没有办法用doctest测试类属性,还是我应该直接编写常规的测试用例?
别担心,这个问题很常见,本质是doctest在运行类内部的docstring时,默认命名空间里没有包含类本身。这里有几个可行的解决办法:
方法1:在doctest中使用相对引用
你可以在示例里用self.__class__来引用当前类,这样不需要直接写类名,就能绕开命名空间的问题:
@property def attribute_squared(self): """ Examples: >>> self.__class__(attribute=2).attribute_squared 4 """ return self.attribute ** 2
不过这个方法有个小限制:只适用于实例方法/属性的docstring,如果是类方法或静态方法的场景就不适用,但对你当前的@property测试完全够用。
方法2:给doctest注入全局命名空间
另一种更通用的方式是在模块级别添加配置,把类注入到doctest的全局环境里。在你的模块末尾加上这段代码:
__test__ = { 'ExampleClass': ExampleClass, }
或者更灵活地直接调用doctest的测试方法并指定globs:
import doctest doctest.testmod(globs={'ExampleClass': ExampleClass})
如果是用py.test,也可以在项目的pytest.ini里配置默认globs,但上面的模块级配置更直接,不需要改动全局配置。
方法3:改用常规测试用例(可选)
如果觉得doctest的命名空间问题有点繁琐,也可以直接写py.test的常规测试用例,可读性和扩展性反而更好:
def test_attribute_squared(): obj = ExampleClass(2) assert obj.attribute_squared == 4
这种方式没有命名空间的限制,也更适合复杂的测试场景,比如多参数组合、边界值测试等。
内容的提问来源于stack exchange,提问作者Gustave Coste

