2014-10-18 4 views
5

Я использую нос для коллекции тестов, и я также хочу использовать его плагин doctest. У меня есть модуль, который нуждается в приспособлении, чтобы быть импортируемым. Поэтому я не могу использовать носовые модули, поскольку они загружаются из тестируемого модуля. Есть ли способ указать модули для носа-доктрины вне модуля?Прибор носа-доктрины модуля до импорта модуля

Для некоторых прецедентов опция должна заключаться в обнаружении запуска в рамках доктрины и применении прибора в начале модуля. Мне было бы интересно услышать ответы на этот случай использования.

Однако существуют ситуации, когда это не может работать: когда сбой импорта из-за SyntaxError, код модуля не запускается. В моем случае я в основном разрабатываю код, который совместим с python 2 и python 3 (без 2to3). Однако есть несколько специальных модулей python 3, которые просто не нужно проверять на носу, когда они запускаются под python 2. Какой у меня лучший вариант?

EDIT: MWE (для SyntaxError ситуации)

У меня есть пакет с большим количеством маленьких модулей, некоторые из них используют синтаксис Python 3. Вот структура пакета:

~/pckg/ 
    __init__.py 
    py3only.py 
    ... (other modules) 
    tests/ 
    test_py3only.py 

Некоторых тесты написаны, как 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 

~/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) 

тестирования на Python 3, все проходит тестирование и проходит (запускается из ограждающих папку, например ~):

~ nosetests3 -v --with-doctest pckg 
Doctest: pckg.py3only.fancy_py3_func ... ok 
test_bruteforce (test_py3only.TestFancyFunc) ... ok 

На питоне 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) 

функцию, аналогичную ~/pckg/tests/test_py3only.py:setup_module() может решить эту проблему, если бы я мог получить nose запустить этот код, прежде чем это doctest плагин даже пытается импортировать этот модуль.

Похоже, мой лучший выбор, чтобы написать правильный сценарий тестирования верхнего уровня, который обрабатывает коллекцию тестов ...

+0

модуль не может быть импортирован без X или Y плохо пахнет, то это означает, например, что ни '' pydoc' ни pylint' могут быть использованы в вашем коде. Меняя модуль во время импорта, потому что он находится под проверкой, разыгрывает всю точку тестирования, не так ли? –

+0

У меня есть по существу два случая: Отсутствие внешних зависимостей _optional_ и модулей с использованием нового синтаксиса python 3, протестированного под python 2. В обоих случаях тестирование практически бесполезно, модули недоступны. Я хочу подавить тестовые сбои и, возможно, заменить их сообщениями, что некоторая часть библиотеки недоступна из-за отсутствия зависимостей. – burnpanck

+0

'nosetests -v --with-doctest pckg' вы позволяете Python 2 видеть код Python 3, потому что вы запускаете' --with-doctest' из верхней директории. Запустите тесты как unittest, так и doctest из папки 'tests'. Чтобы doctest смог извлечь его в текстовый файл, как я сделал, чтобы вы могли условно импортировать. –

ответ

2

Специфические тестовые файлы, каталоги, классы или методы можно исключить, используя плагин nose-exclude. Он имеет --exclude-* вариантов.

Для обработки недостающих модулей необходимо исправить sys.modules, используя mock.

F.e, есть класс Calc в модуле mycalc, но у меня нет доступа к нему, потому что он отсутствует. И есть еще два модуля: mysuper_calc и mysuper_calc3, последний - специфический для Python 3. Эти два модуля импортируют mycalc и mysuper_calc3 не должны тестироваться под Python 2. Как учесть их из модуля, то есть в текстовом файле? Я предполагаю, что это положение ОП.

известково/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) 

известково/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) 

Теперь издеваться из mycalc,

>>> from mock import Mock, patch 
>>> mock = Mock(name='mycalc') 

Модуль mycalc имеет класс Calc, который имеет метод add , Я тестирую SuperCalc пример add метод с 2+3.

>>> mock.Calc.add.return_value = 5 

Теперь патч sys.modules и mysuper_calc3 можно условно импортирован в with блоке.

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

известково/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 

Файл mysuper_calc_doctest.txt должен быть один в своем собственном каталоге в противном случае nosetests ищет doctest в неэмиссионные тестовых модулей.

PYTHONPATH=.. nosetests --with-doctest --doctest-extension=txt --verbosity=3 

Doctest: mysuper_calc_doctest.txt ... хорошо


Ран 1 тест в 0.038s

OK

обертка вокруг nosetests обнаружить Python 3, который проходит .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) 
+1

Конечно, исправление 'sys.modules' с модульными модулями было бы одним из возможных действий, которые мог бы сделать мой прибор, чтобы сделать их импортируемыми. Проблема в том, где я размещаю этот код прибора, так что 'нос' запускает его до того, как' nose-doctest' пытается импортировать модуль? – burnpanck

+1

Кроме того, в то время как 'нос-исключение' позволило мне исключить файлы из синтаксиса python 3 из тестов, он позволяет сделать это только статически из файла' node.cfg' или из командной строки. Я предпочел бы, чтобы устройство приняло решение о пропуске, так как я просто хочу пропустить при тестировании python 2, но не при тестировании python 3 и без ручного взаимодействия. – burnpanck

+1

«приспособление» в вашем контексте неясно. Покажите нам примерный код, описывающий вашу ситуацию, «нос» не может импортировать и «fixutre» принимает решение о пропуске. –

1

Нос имеет следующий вариант:

--doctest-fixtures=SUFFIX 
        Find fixtures for a doctest file in module with this 
        name appended to the base name of the doctest file 

Возможно, вы можете изолировать приспособления для отдельного файла?

+1

Звучит интересно, важный вопрос в том, будет ли светильник работать до импорта модуля. Я сделаю это. – burnpanck

+1

К сожалению, '--doctest-fixtures' рассматривается только для _non-module_ doctests. Поэтому это не может помочь мне скрыть 'SyntaxError' во время импорта, когда doctest ищет модули для тестов. Спасибо за ответ! – burnpanck

Смежные вопросы