2014-10-18 13 views
5

Io uso il naso per la raccolta di test e voglio anche usare il suo plugin doctest. Ho un modulo che ha bisogno di un dispositivo per essere importuno. Pertanto, non posso utilizzare i dispositivi del modulo del naso, dal momento che sono caricati dal modulo sotto test. C'è un modo per specificare i dispositivi del modulo per nose-doctest al di fuori del modulo?fixture modulo nose-doctest prima che il modulo venga importato

Per alcuni casi d'uso, un'opzione potrebbe essere quella di rilevare l'esecuzione sotto doctest e l'applicazione del dispositivo all'inizio del modulo. Sarei interessato anche a sentire le risposte per questo caso d'uso.

Tuttavia, ci sono situazioni in cui questo non funziona: quando l'importazione non riesce a causa di un SyntaxError, non viene mai eseguito alcun codice modulo. Nel mio caso, sto principalmente sviluppando un codice che sia compatibile con python 2 e python 3 (senza 2to3). Esistono tuttavia alcuni moduli specifici di python 3, che semplicemente non dovrebbero essere controllati del tutto dal naso, quando si esegue sotto python 2. Quale sarebbe la mia migliore opzione qui?

EDIT: MWE (per la situazione SyntaxError)

Ho un pacchetto con molti piccoli moduli, alcuni di loro usano pitone 3 sintassi. Ecco la struttura del pacchetto:

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

Alcuni test sono scritti come unittest.TestCase, ma voglio anche gli esempi di codice nelle docstring testati. ~/pckg/__init__.py è vuoto.

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

test su Python 3, tutto diventa testati e passa (eseguiti dalla racchiudendo cartella, ad esempio ~):

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

il pitone 2, l'apparecchio modulo di ~/pckg/tests/test_py2only.py rileva correttamente la situazione e salta il test. Tuttavia, otteniamo un SyntaxError da ~/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) 

una funzione simile a ~/pckg/tests/test_py3only.py:setup_module() potrebbe risolvere il problema, se potessi ottenere nose per eseguire il codice prima che sia doctest plug anche tenta di importare quel modulo.

Sembra che la mia scommessa migliore è quello di scrivere una vera e propria script di test di livello superiore che si occupa della raccolta delle prove ...

+0

modulo non può essere importato senza X o Y cattivo odore, che significa, ad esempio, che né '' pydoc' né pylint' possono essere utilizzati sul vostro codice. Cambiare modulo al momento dell'importazione perché è in fase di test, sconfigge l'intero punto di test, vero? –

+0

Ho essenzialmente due casi: le dipendenze esterne _optional_ mancanti e i moduli che usano la nuova sintassi python 3, testati sotto python 2. In entrambi i casi, il test è essenzialmente vano, i moduli non sono disponibili. Voglio sopprimere i fallimenti del test e magari sostituirli con messaggi, che alcune parti della libreria non sono disponibili a causa di dipendenze mancanti. – burnpanck

+0

'nosetests -v --with-doctest pckg' consente a Python 2 di vedere il codice Python 3 perché si esegue' --with-doctest' dalla directory principale. Esegui i test sia unittest che doctest dalla cartella 'tests'. Perché doctest riesca a estrarlo in un file di testo normale come ho fatto in modo che tu possa importare condizionalmente. –

risposta

2

File di test specifici, directory, classi o metodi possono essere esclusi utilizzando il plug-in nose-exclude. Ha opzioni --exclude-*.

Per gestire i moduli mancanti, è necessario correggere sys.modules utilizzando mock.

F.e, C'è una classe Calc nel modulo mycalc, ma non ho accesso perché manca. E ci sono altri due moduli, mysuper_calc e mysuper_calc3, quest'ultimo è specifico per Python 3. Questi due moduli importano mycalc e mysuper_calc3 non dovrebbero essere testati in Python 2. Come doctestarli dal modulo, che è in un file di testo normale? Presumo che questa sia la situazione dell'OP.

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

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

Ora per mock mycalc,

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

modulo mycalc ha classe Calc che ha metodo add . Prova il metodo SuperCalc istanza add con 2+3.

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

Ora rattoppare sys.modules e mysuper_calc3 può essere condizionatamente importati all'interno del blocco with.

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

calc/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 

Il file mysuper_calc_doctest.txt deve essere solo nella propria directory altrimenti nosetests ricerche per doctest a moduli non-test.

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

doctest: mysuper_calc_doctest.txt ... ok


Ran 1 test in 0.038s

OK

Wrapper attorno nosetests per rilevare Python 3 che passa .py file senza errori di sintassi su 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

Certo, l'applicazione di 'sys.modules' con i moduli mock sarebbe una delle possibili azioni che il mio dispositivo potrebbe fare per renderle irripetibili. Il problema è, dove metto questo codice del dispositivo, in modo tale che 'nose' lo esegua prima che' nose-doctest' tenti di importare il modulo? – burnpanck

+1

Inoltre, mentre 'nose-exclude' mi consente di escludere i file con la sintassi python 3 dai test, consente solo di farlo staticamente dal file' node.cfg' o dalla riga di comando. Avrei preferito lasciare che un dispositivo decidesse di saltare, dato che voglio saltare solo quando collaudo python 2, ma non quando collaudo python 3 e senza alcuna interazione manuale. – burnpanck

+1

"fixture" nel tuo contesto non è chiaro. Mostraci un codice di esempio, descrivendo la tua situazione, 'nose' non può importare e' fixutre 'decidere di saltare. –

1

naso ha seguente opzione:

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

Forse si può isolare proiettori su un file separato?

+1

Sembra interessante, la domanda importante è se l'apparecchiatura verrà eseguita prima che il modulo venga importato. Darò un colpo. – burnpanck

+1

Sfortunatamente, '--doctest-fixtures' è considerato solo per i documest__non-module_. Pertanto, questo non può aiutarmi a nascondere 'SyntaxError's durante l'importazione quando doctest cerca i moduli per i test.Grazie comunque per la risposta! – burnpanck