pdb在Django文档测试中无效
我创建了一个文件(testlib.py),目的是自动加载我项目中所有目录里的文档测试(doctests),并把它们放到 __tests__
字典里,这个字典是在 tests.py 文件中。
# ./testlib.py
import os, imp, re, inspect
from django.contrib.admin import site
def get_module_list(start):
all_files = os.walk(start)
file_list = [(i[0], (i[1], i[2])) for i in all_files]
file_dict = dict(file_list)
curr = start
modules = []
pathlist = []
pathstack = [[start]]
while pathstack is not None:
current_level = pathstack[len(pathstack)-1]
if len(current_level) == 0:
pathstack.pop()
if len(pathlist) == 0:
break
pathlist.pop()
continue
pathlist.append(current_level.pop())
curr = os.sep.join(pathlist)
local_files = []
for f in file_dict[curr][1]:
if f.endswith(".py") and os.path.basename(f) not in ('tests.py', 'models.py'):
local_file = re.sub('\.py$', '', f)
local_files.append(local_file)
for f in local_files:
# This is necessary because some of the imports are repopulating the registry, causing errors to be raised
site._registry.clear()
module = imp.load_module(f, *imp.find_module(f, [curr]))
modules.append(module)
pathstack.append([sub_dir for sub_dir in file_dict[curr][0] if sub_dir[0] != '.'])
return modules
def get_doc_objs(module):
ret_val = []
for obj_name in dir(module):
obj = getattr(module, obj_name)
if callable(obj):
ret_val.append(obj_name)
if inspect.isclass(obj):
ret_val.append(obj_name)
return ret_val
def has_doctest(docstring):
return ">>>" in docstring
def get_test_dict(package, locals):
test_dict = {}
for module in get_module_list(os.path.dirname(package.__file__)):
for method in get_doc_objs(module):
docstring = str(getattr(module, method).__doc__)
if has_doctest(docstring):
print "Found doctests(s) " + module.__name__ + '.' + method
# import the method itself, so doctest can find it
_temp = __import__(module.__name__, globals(), locals, [method])
locals[method] = getattr(_temp, method)
# Django looks in __test__ for doctests to run. Some extra information is
# added to the dictionary key, because otherwise the info would be hidden.
test_dict[method + "@" + module.__file__] = getattr(module, method)
return test_dict
在这里,我要感谢一些来源,很多内容来自于 这个链接
在我的 tests.py 文件中,我写了以下代码:
# ./project/tests.py
import testlib, project
__test__ = testlib.get_test_dict(project, locals())
这些代码运行得很好,可以从我所有的文件和子目录中加载文档测试。但是,问题是,当我在任何地方调用 pdb.set_trace() 时,我看到的只有这些:
(Pdb) l
(Pdb) args
(Pdb) n
(Pdb) n
(Pdb) l
(Pdb) cont
看起来 doctest 正在捕捉和处理输出,并用这些输出去评估测试结果。所以,当测试运行结束后,我看到的都是在 pdb 调试环境中应该打印出来的内容,这些内容出现在 doctest 的失败报告里。不管我是在 doctest 的某一行里调用 pdb.set_trace(),还是在被测试的函数或方法里调用,都会出现这个问题。
显然,这让人很沮丧。文档测试很好,但没有交互式的 pdb,我就无法调试它们检测到的任何失败,进而去修复它们。
我在想,或许可以把 pdb 的输出流重定向到某个地方,这样就能绕过 doctest 对输出的捕捉,但我需要一些帮助来搞清楚需要哪些底层的输入输出操作。而且,我甚至不知道这是否可行,对 doctest 的内部机制也不太熟悉,不知道从哪里开始。有谁能给点建议,或者更好的是,提供一些可以实现这个功能的代码吗?
1 个回答
4
我通过一些调整成功使用了pdb调试器。我只是在我的testlib.py文件的底部加了以下代码:
import sys, pdb
class TestPdb(pdb.Pdb):
def __init__(self, *args, **kwargs):
self.__stdout_old = sys.stdout
sys.stdout = sys.__stdout__
pdb.Pdb.__init__(self, *args, **kwargs)
def cmdloop(self, *args, **kwargs):
sys.stdout = sys.__stdout__
retval = pdb.Pdb.cmdloop(self, *args, **kwargs)
sys.stdout = self.__stdout_old
def pdb_trace():
debugger = TestPdb()
debugger.set_trace(sys._getframe().f_back)
为了使用这个调试器,我只需要 import testlib
然后调用 testlib.pdb_trace()
,这样就可以进入一个功能齐全的调试器了。