Występuje tajemniczy błąd importowania, gdy używam testów nosa do uruchomienia zestawu testów, którego nie mogę odtworzyć poza nosem. Ponadto błąd importu znika, gdy pomijam podzbiór testów.Błąd importowania podczas wykonywania testów nosa, których nie mogę odtworzyć poza nosem.
Streszczenie: Dostaję błąd importu w nosie, że a) pojawia się tylko wtedy, gdy testy namiar pewien atrybut są wyłączone oraz b) nie może być powielana w sesji interaktywnej python, nawet kiedy zapewnienia, że sys. ścieżka jest taka sama dla obu.
Szczegóły:
Struktura pakietu wygląda tak:
project/
module1/__init__.py
module1/foo.py
module1/test/__init__.py
module1/test/foo_test.py
module1/test/test_data/foo_test_data.txt
module2/__init__.py
module2/bar.py
module2/test/__init__.py
module2/test/bar_test.py
module2/test/test_data/bar_test_data.txt
Niektóre z testów w foo_test.py są powolne, więc stworzyliśmy dekorator @slow aby umożliwić mi pomiń je z opcją nosetests:
def slow(func):
"""Decorator sets slow attribute on a test method, so
nosetests can skip it in quick test mode."""
func.slow = True
return func
class TestFoo(unittest.TestCase):
@slow
def test_slow_test(self):
load_test_data_from("test_data/")
slow_test_operations_here
def test_fast_test(self):
load_test_data_from("test_data/")
Gdy chcę uruchomić tylko szybkich testów jednostkowych, używam
nosetests -vv -a'!slow'
z katalogu głównego projektu. Kiedy chcę je wszystkie uruchomić, usuwam ostatni argument.
Nadchodzi szczegół, który, jak podejrzewam, jest odpowiedzialny za ten bałagan. Testy jednostkowe muszą załadować dane testowe z plików (w przeciwieństwie do najlepszej praktyki). Pliki są umieszczane w katalogu o nazwie "test_data" w każdym pakiecie testowym, a kod testu jednostkowego odnosi się do nich względną ścieżką, zakładając, że test jednostkowy uruchamiany jest z katalogu test /, jak pokazano w powyższym przykładowym kodzie.
Aby uzyskać to do pracy z systemem nos z katalogu głównego projektu I dodaje następujący kod do Init .py w każdym opakowaniu testu:
import os
import sys
orig_wd = os.getcwd()
def setUp():
"""
test package setup: change working directory to the root of the test package, so that
relative path to test data will work.
"""
os.chdir(os.path.dirname(os.path.abspath(__file__)))
def tearDown():
global orig_wd
os.chdir(orig_wd)
O ile mi zrozumieć, nos wykonuje metody pakietów setUp i tearDown przed i po uruchomieniu testów w tym pakiecie, co zapewnia, że test jednostki może znaleźć odpowiedni katalog test_data, a katalog roboczy zostanie zresetowany do pierwotnej wartości po zakończeniu testów.
Tyle o konfiguracji. Problem polega na tym, że pojawia się błąd importowania tylko po uruchomieniu pełnego zestawu testów. Te same moduły importują się dobrze, gdy wykluczam wolne testy. (Dla wyjaśnienia, testy rzucanie błędy importu nie są powolne, więc wykonać w każdym scenariuszu.)
$ nosetests
...
ERROR: Failure: ImportError (No module named foo_test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/nose/loader.py", line 413, in loadTestsFromName
addr.filename, addr.module)
File "/Library/Python/2.7/site-packages/nose/importer.py", line 47, in importFromPath
return self.importFromDir(dir_path, fqname)
File "/Library/Python/2.7/site-packages/nose/importer.py", line 80, in importFromDir
fh, filename, desc = find_module(part, path)
ImportError: No module named foo_test
Jeśli uruchomić zestaw testów bez wolnych testów, to nie błąd:
$ nosetests -a'!slow'
...
test_fast_test (module1.test.foo_test.TestFoo) ... ok
w python interaktywnej sesji, mogę zaimportować moduł testowy bez kłopotów:
$ python
Python 2.7.1 (r271:86832, Aug 5 2011, 03:30:24)
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import module1.test
>>> module1.test.__path__
['/Users/USER/project/module1/test']
>>> dir(module1.test)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'orig_wd', 'os', 'setUp', 'sys', 'tearDown']
Kiedy ustawić punkt przerwania w nosie/importer.py, wszystko wygląda inaczej:
> /Library/Python/2.7/site-packages/nose/importer.py(83)importFromDir()
-> raise
(Pdb) l
78 part, part_fqname, path)
79 try:
80 fh, filename, desc = find_module(part, path)
81 except ImportError, e:
82 import pdb; pdb.set_trace()
83 -> raise
84 old = sys.modules.get(part_fqname)
85 if old is not None:
86 # test modules frequently have name overlap; make sure
87 # we get a fresh copy of anything we are trying to load
88 # from a new path
(Pdb) part
'foo_test'
(Pdb) path
['/Users/USER/project/module1/test']
(Pdb) import module1.test.foo_test
*** ImportError: No module named foo_test
#If I import module1.test, it works, but the __init__.py file is not being executed
(Pdb) import partition.test
(Pdb) del dir
(Pdb) dir(partition.test)
['__doc__', '__file__', '__name__', '__package__', '__path__'] #setUp and tearDown missing?
(Pdb) module1.test.__path__
['/Users/USER/project/module1/test'] #Module path is the same as before.
(Pdb) os.listdir(partition.test.__path__[0]) #All files are right where they should be...
['.svn', '__init__.py', '__init__.pyc', 'foo_test.py', 'foo_test.pyc','test_data']
Widzę te same nieprzyjemne wyniki, nawet jeśli skopiowałem sys.ścieżkę z mojej interaktywnej sesji do sesji pdb i powtórz powyższe. Czy ktokolwiek może mi dać wgląd w to, co się dzieje? Zdaję sobie sprawę, że robię kilka niestandardowych rzeczy w tym samym czasie, co może prowadzić do dziwnych interakcji. Byłbym zainteresowany poradą, jak uprościć moją architekturę, ponieważ chciałbym uzyskać wyjaśnienie tego błędu.
Aby potwierdzić, nie masz "__init __. Py" w projekcie, prawda? – alecxe
Zgadza się. Nie __init__.py w projekcie reż. Widziałem te pytania tam, gdzie to było dyskutowane, ale nie do końca rozumiem, dlaczego to ma znaczenie. Wiesz dlaczego? –
Nie całkiem to rozumiem, ale chodzi o to, jak działa [importer nosa] (https://github.com/nose-devs/nose/blob/master/nose/importer.py). Zobacz także: http://stackoverflow.com/questions/16174649/specially-named-directories-using-nosetests/16224909#16224909. – alecxe