I. Vorwort: Die Anwendungsverzeichnisstruktur und Module sind am Ende des Beitrags aufgeführt.Python Run Unittest als Paket Import Fehler
II. Problembeschreibung: Wenn PYTHONPATH nicht festgelegt ist, wird die Anwendung ausgeführt, aber der Komponententest schlägt fehl ImportError: Kein Modul namens models.transactions. Dies geschieht, wenn Sie versuchen, Transactions in app.py zu importieren. Wenn der PYTHONPATH auf /sandbox/app
eingestellt ist, werden sowohl die Anwendung als auch der Unit Test ohne Fehler ausgeführt. Die Einschränkungen für eine Lösung bestehen darin, dass der PYTHONPATH nicht festgelegt werden sollte, und der sys.path sollte nicht programmgesteuert geändert werden müssen.
III. Details: Betrachten Sie den Fall, wenn der PYTHONPATH eingestellt ist und test_app.py
als Paket /sandbox$ python -m unittest tests.test_app
ausgeführt wird. Mit Blick auf den Druckanweisungen für __main__
über den gesamten Code gestreut:
models : app.models.transactions
models : models.transactions
resources: app.resources.transactions
app : app.app
test : tests.test_app
Der Unittest die App importiert zuerst, und so ist es app.models.transactions
. Der nächste Import, den die App versucht, ist resources.transactions
. Wenn es importiert wird, macht es seinen eigenen Import von models.transactions
und dann sehen wir die __name__
für app.resources.transactions
. Danach folgt der app.app
Import und schließlich das Unittest-Modul tests.test.app
. Wenn Sie PYTHONPATH einstellen, kann die Anwendung models.transactions auflösen!
Eine Lösung ist die models.transactions
innerhalb resources.transaction
zu setzen. Aber gibt es einen anderen Weg, mit dem Problem umzugehen?
Für Vollständigkeit, wenn die Anwendung der Druck ausgeführt wird Anweisungen für __main__
sind:
models : models.transactions
resources: resources.transactions
app : __main__
Dies ist zu erwarten, und keine Importe versucht werden, die oben /sandbox/app
oder seitlich sind.
IV. Appendix
A.1 Verzeichnisstruktur:
|-- sandbox
|-- app
|-- models
|-- __init__.py
|-- transactions.py
|-- resources
|-- __init__.py
|-- transactions.py
|-- __init__.py
|-- app.py
|-- tests
|-- __init__.py
|-- test_app.py
A.2 Module:
(1) APP:
from flask import Flask
from models.transactions import TransactionsModel
from resources.transactions import Transactions
print ' app : ', __name__
def create_app():
app = Flask(__name__)
return app
app = create_app()
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000, debug=True)
(2) models.transactions
print ' model : ', __name__
class TransactionsModel:
pass
(3) resources.transactions:
from models.transactions import TransactionsModel
print ' resources: ', __name__
class Transactions:
pass
(4) Tests.test_app
import unittest
from app.app import create_app
from app.resources.transactions import Transactions
print ' test : ', __name__
class DonationTestCase(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_transactions_get_with_none_ids(self):
self.assertEqual(0, 0)
if __name__ == '__main__':
unittest.main()
Die Tatsache, dass "es funktioniert" sollte gegen die Tatsache gewichtet werden, dass dieser Code nicht sehr "lesbar" ist: Mit anderen Worten, andere Leute, die mit der Pflege des Codes beauftragt sind, würden wirklich Schwierigkeiten haben, alles zu verstehen, was Sie hier tun (v. einfach "Wrapper" -Shellskripte bereitstellen, die "das Richtige" tun. Auch wenn Sie weitere Tests/Module hinzufügen, habe ich den Eindruck, dass dies schnell ziemlich unhandlich werden würde. – Marco
Absolut! Nicht die Art und Weise, mit Importen umzugehen, es sei denn, es gibt Einschränkungen, wo man den Python-Pfad sys.path usw. nicht ändern darf. Am Ende, wie ich im ersten Absatz erwähnt habe, besteht die Möglichkeit, FLASK_APP zu setzen , und führen Sie sowohl die App als auch den Unittest als Pakete aus. – Aaron