Ich stoße auf einen mysteriösen Importfehler bei der Verwendung von Nasetests, um eine Testsuite auszuführen, die ich außerhalb der Nase nicht reproduzieren kann. Darüber hinaus verschwindet der Importfehler, wenn ich eine Teilmenge der Tests überspringe.Importfehler beim Ausführen von Nasetests, die ich außerhalb der Nase nicht reproduzieren kann
Zusammenfassung: Ich bekomme einen Importfehler in Nase, dass a) nur erscheint, wenn Tests mit einem bestimmten Attribut ausgeschlossen sind und b) nicht in einer interaktiven Python-Sitzung reproduziert werden kann, auch wenn ich dafür sorge. Der Weg ist für beide gleich.
Details:
Die Paketstruktur sieht wie folgt aus:
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
Einige der Tests in foo_test.py langsam sind, so habe ich ein @slow Dekorateur erstellt mir zu erlauben, überspringen sie mit einer nosetests Option:
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/")
Wenn ich nur die schnelle Unit-Tests ausführen möchten, verwende ich
nosetests -vv -a'!slow'
aus dem Stammverzeichnis des Projekts. Wenn ich sie alle ausführen will, entferne ich das letzte Argument.
Hier kommt das Detail, von dem ich vermute, dass es für dieses Chaos verantwortlich ist. Die Komponententests müssen Testdaten aus Dateien laden (nicht Best Practice, die ich kenne.) Die Dateien werden in jedem Testpaket in ein Verzeichnis namens "test_data" gestellt, und der Komponententestcode bezieht sich auf sie durch einen relativen Pfad Der Komponententest wird aus dem test/-Verzeichnis ausgeführt, wie im obigen Beispielcode gezeigt.
dies mit laufender Nase aus dem Stammverzeichnis des Projektes zur Arbeit zu kommen, habe ich den folgenden Code init Py in jedem Paket Test:
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)
Soweit ich verstehe, Nase Führt die Paketmethoden setUp und tearDown vor und nach dem Ausführen der Tests in diesem Paket aus. Dadurch wird sichergestellt, dass der Komponententest das entsprechende Verzeichnis test_data finden kann. Wenn die Tests abgeschlossen sind, wird das Arbeitsverzeichnis auf den ursprünglichen Wert zurückgesetzt.
So viel für die Einrichtung. Das Problem ist, bekomme ich einen Importfehler nur, wenn ich die vollständige Suite von Tests ausführen. Die gleichen Module importieren sich gut, wenn ich die langsamen Tests ausschließe. (Um zu klären, werfen die Tests Importfehler sind nicht langsam, so dass sie durchführen in beiden Szenarien.)
$ 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
Wenn ich die Testsuite ohne die langsamen Tests laufen, dann kein Fehler:
$ nosetests -a'!slow'
...
test_fast_test (module1.test.foo_test.TestFoo) ... ok
in einer python interaktive Sitzung, kann ich das Testmodul ohne Probleme importieren:
$ 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']
Wenn ich einen Haltepunkt in der Nase/importer.py gesetzt, sieht die Sache anders aus:
> /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']
Ich sehe die gleichen screwy Ergebnisse, auch wenn ich sys kopieren.Pfad von meiner interaktiven Sitzung in die PDB-Sitzung und wiederholen Sie die oben genannten. Kann mir irgendjemand etwas darüber sagen, was vor sich geht? Ich merke, dass ich mehrere nicht standardmäßige Dinge gleichzeitig mache, was zu seltsamen Interaktionen führen kann. Ich wäre genauso interessiert an Ratschlägen, wie ich meine Architektur vereinfachen könnte, um eine Erklärung für diesen Fehler zu erhalten.
Nur um zu bestätigen, haben Sie nicht '__init __. Py' im Projektverzeichnis, richtig? – alecxe
Das stimmt. Nein __init__.py im Projektverzeichnis Ich habe diese Fragen gesehen, wo das diskutiert wurde, aber verstehe nicht ganz, warum das wichtig ist. Weißt du, warum? –
Ich verstehe es auch nicht ganz, aber es geht darum, wie [Nose Importeur] (https://github.com/nose-devs/nose/blob/master/nose/importer.py) funktioniert. Siehe auch: http://StackOverflow.com/Questions/16174649/Special-Anamed-Directories-using-Nosetests/16224909#16224909. – alecxe