导入模块之前的nose-doctest模块夹具

bur*_*nck 5 python testing doctest nose

我使用鼻子进行测试收集,我也想使用它的doctest插件.我有一个模块,需要一个夹具才能导入.因此,我不能使用鼻子的模块固定装置,因为它们是从被测模块加载的.有没有办法在模块外部为nose-doctest指定模块夹具?

对于某些用例,一个选项是检测在doctest下运行并在模块的开头应用fixture.我很想知道这个用例的答案.

但是,在某些情况下,这不起作用:当导入因a而失败时SyntaxError,不会运行任何模块代码.在我的例子中,我主要开发的代码兼容python 2和python 3(没有2to3).然而,有一些python 3特定模块,当在python 2下运行时根本不应该由鼻子检查.我最好的选择是什么?

编辑:MWE(针对这种SyntaxError情况)

我有一个包含许多小模块的包,其中一些使用python 3语法.这是包结构:

~/pckg/
  __init__.py
  py3only.py
  ... (other modules)
  tests/
    test_py3only.py
Run Code Online (Sandbox Code Playgroud)

有些测试是作为编写的unittest.TestCase,但我也希望测试文档字符串中的代码示例.~/pckg/__init__.py是空的.

〜/ pckg/py3only.py:

def fancy_py3_func(a:"A function argument annotation (python 3 only syntax)"):
    """ A function using fancy syntax doubling it's input.

    >>> fancy_py3_func(4)
    8
    """
    return a*2
Run Code Online (Sandbox Code Playgroud)

〜/ pckg /测试/ test_py3only.py:

import sys, unittest

def setup_module():
    if sys.version_info[0] < 3:
        raise unittest.SkipTest("py3only unavailable on python "+sys.version)

class TestFancyFunc(unittest.TestCase):
    def test_bruteforce(self):
        from pckg.py3only import fancy_py3_func
        for k in range(10):
            self.assertEqual(fancy_py3_func(k),2*k)
Run Code Online (Sandbox Code Playgroud)

在python 3上测试,一切都经过测试和传递(从封闭文件夹运行,例如~):

~ nosetests3 -v --with-doctest pckg
Doctest: pckg.py3only.fancy_py3_func ... ok
test_bruteforce (test_py3only.TestFancyFunc) ... ok
Run Code Online (Sandbox Code Playgroud)

在python 2上,模块夹具~/pckg/tests/test_py2only.py正确检测情况并跳过测试.但是,我们得到一个SyntaxError来自~/pckg/py3only.py:

~ nosetests -v --with-doctest pckg 
Failure: SyntaxError (invalid syntax (py3only.py, line 1)) ... ERROR
SKIP: py3only unavailable on python 2.7.6 (default, Mar 22 2014, 22:59:56)
Run Code Online (Sandbox Code Playgroud)

一个类似的函数~/pckg/tests/test_py3only.py:setup_module()可以解决这个问题,如果我可以nose在它的doctest插件之前运行该代码甚至尝试导入该模块.

看起来我最好的办法是编写一个适当的顶级测试脚本来处理测试的集合......

Niz*_*med 2

可以使用鼻子排除鼻子插件排除特定的测试文件、目录、类或方法。它有--exclude-*选项。

要处理丢失的模块,您必须sys.modules使用mock.

Fe,模块中有一个Calcmycalc,但我无法访问它,因为它丢失了。还有两个模块,mysuper_calcmysuper_calc3,后者是 Python 3 特定的。这两个模块是导入的mycalcmysuper_calc3不应在 Python 2 下进行测试。如何在纯文本文件中的模块中对它们进行文档测试?我想这就是OP的情况。

计算/mysuper_calc3.py

from sys import version_info
if version_info[0] != 3:
    raise Exception('Python 3 required')
from mycalc import Calc
class SuperCalc(Calc):
    '''This class implements an enhanced calculator
    '''
    def __init__(self):
        Calc.__init__(self)

    def add(self, n, m):
        return Calc.add(self, n, m)
Run Code Online (Sandbox Code Playgroud)

计算/mysuper_calc.py

from mycalc import Calc

class SuperCalc(Calc):
    '''This class implements an enhanced calculator
    '''
    def __init__(self):
        Calc.__init__(self)

    def add(self, n, m):
        return Calc.add(self, n, m)
Run Code Online (Sandbox Code Playgroud)

现在模拟一下mycalc

>>> from mock import Mock, patch
>>> mock = Mock(name='mycalc')
Run Code Online (Sandbox Code Playgroud)

模块具有包含方法的mycalc类。我用 测试实例方法。 CalcaddSuperCalcadd2+3

>>> mock.Calc.add.return_value = 5  
Run Code Online (Sandbox Code Playgroud)

现在修补sys.modulesmysuper_calc3可以有条件地导入到with块内。

>>> with patch.dict('sys.modules',{'mycalc': mock}):
...     from mysuper_calc import SuperCalc
...     if version_info[0] == 3:
...         from mysuper_calc3 import SuperCalc
Run Code Online (Sandbox Code Playgroud)

计算/doctest/mysuper_calc_doctest.txt

>>> from sys import version_info
>>> from mock import Mock, patch
>>> mock = Mock(name='mycalc')
>>> mock.Calc.add.return_value = 5

>>> with patch.dict('sys.modules',{'mycalc': mock}):
...     from mysuper_calc import SuperCalc
...     if version_info[0] == 3:
...         from mysuper_calc3 import SuperCalc
>>> c = SuperCalc()
>>> c.add(2,3)
5
Run Code Online (Sandbox Code Playgroud)

该文件mysuper_calc_doctest.txt必须单独位于其自己的目录中,否则将在非测试模块中 nosetests搜索。doctest

PYTHONPATH=.. nosetests --with-doctest --doctest-extension=txt --verbosity=3
Run Code Online (Sandbox Code Playgroud)

Doctest: mysuper_calc_doctest.txt ... 好的


在 0.038 秒内运行 1 次测试

好的

用于检测 Python 3 的包装器nosetests,它将没有语法错误的 .py 文件传递​​给nosetests

mynosetests.py

import sys
from subprocess import Popen, PIPE
from glob import glob

f_list = []

py_files = glob('*py')
try:
    py_files.remove(sys.argv[0])
except ValueError:
    pass

for py_file in py_files:
    try:
        exec open(py_file)
    except SyntaxError:
        continue
    else:
        f_list.append(py_file)

proc = Popen(['nosetests'] + sys.argv[1:] + f_list,stdout=PIPE, stderr=PIPE)
print('%s\n%s' % proc.communicate())
sys.exit(proc.returncode)
Run Code Online (Sandbox Code Playgroud)