wake-up-neo.com

Wird nur mit der typischen Testverzeichnisstruktur ausgeführt

Die übliche Verzeichnisstruktur selbst für ein einfaches Python-Modul scheint die Komponententests in ihr eigenes test-Verzeichnis zu trennen:

new_project/
    antigravity/
        antigravity.py
    test/
        test_antigravity.py
    setup.py
    etc.

siehe zum Beispiel dieses Python-Projekt Howto .

Meine Frage ist einfach Wie läuft eigentlich der Test ab? Ich vermute, das ist jedem außer mir offensichtlich, aber Sie können python test_antigravity.py nicht einfach aus dem Testverzeichnis ausführen, da dessen import antigravity fehlschlägt, da sich das Modul nicht im Pfad befindet.

Ich weiß, ich könnte PYTHONPATH und andere Tricks zum Suchpfad modifizieren, aber ich kann nicht glauben, dass dies der einfachste Weg ist. Es ist in Ordnung, wenn Sie Entwickler sind, aber nicht realistisch erwarten, dass Ihre Benutzer sie verwenden, wenn sie nur die Tests überprüfen möchten Vorbeigehen.

Die andere Alternative besteht darin, die Testdatei einfach in das andere Verzeichnis zu kopieren, aber es scheint etwas dumm zu sein und verpasst den Punkt, sie in einem separaten Verzeichnis zu haben, um damit zu beginnen.

Wenn Sie also gerade die Quelle in mein neues Projekt heruntergeladen hätten, wie würden Sie dann die Komponententests ausführen? Ich würde eine Antwort vorziehen, die mich zu meinen Benutzern sagen lässt: "Um die Unit-Tests auszuführen, machen Sie X."

553
Major Major

Meiner Meinung nach ist die beste Lösung die Verwendung der unittestBefehlszeilenschnittstelle , die das Verzeichnis zum sys.path hinzufügt, so dass dies nicht erforderlich ist (in der TestLoader-Klasse).

Zum Beispiel für eine Verzeichnisstruktur wie folgt:

new_project
├── antigravity.py
└── test_antigravity.py

Du kannst einfach laufen:

$ cd new_project
$ python -m unittest test_antigravity

Für eine Verzeichnisstruktur wie Ihre:

new_project
├── antigravity
│   ├── __init__.py         # make it a package
│   └── antigravity.py
└── test
    ├── __init__.py         # also make test a package
    └── test_antigravity.py

In den Testmodulen im Paket test können Sie das Paket antigravity und seine Module wie üblich importieren:

# import the package
import antigravity

# import the antigravity module
from antigravity import antigravity

# or an object inside the antigravity module
from antigravity.antigravity import my_object

Ausführen eines einzelnen Testmoduls:

Um ein einzelnes Testmodul auszuführen, in diesem Fall test_antigravity.py:

$ cd new_project
$ python -m unittest test.test_antigravity

Verweisen Sie das Testmodul einfach so, wie Sie es importieren.

Ausführen eines einzelnen Testfalls oder einer Testmethode:

Sie können auch eine einzelne TestCase oder eine einzelne Testmethode ausführen:

$ python -m unittest test.test_antigravity.GravityTestCase
$ python -m unittest test.test_antigravity.GravityTestCase.test_method

Alle Tests ausführen:

Sie können auch Test Discovery verwenden, um alle Tests für Sie zu ermitteln und auszuführen. Dies müssen Module oder Pakete mit dem Namen test*.py sein (kann mit dem Flag -p, --pattern geändert werden):

$ cd new_project
$ python -m unittest discover

Dadurch werden alle test*.py-Module im test-Paket ausgeführt.

520
Pierre

Die einfachste Lösung für Ihre Benutzer besteht darin, ein ausführbares Skript (runtests.py oder ein ähnliches Skript) zur Verfügung zu stellen, das die erforderliche Testumgebung bootstraps, einschließlich eines temporären Hinzufügen des Stammprojektverzeichnisses zu sys.path. Dies erfordert nicht, dass Benutzer Umgebungsvariablen festlegen. In einem Bootstrap-Skript funktioniert dies ungefähr so:

import sys, os

sys.path.insert(0, os.path.dirname(__file__))

Dann können Ihre Anweisungen an Ihre Benutzer so einfach sein wie "python runtests.py".

Wenn der Pfad, den Sie wirklich benötigen, os.path.dirname(__file__) ist, müssen Sie ihn natürlich nicht zu sys.path hinzufügen. Python setzt das Verzeichnis des aktuell laufenden Skripts immer am Anfang von sys.path. Abhängig von Ihrer Verzeichnisstruktur reicht es möglicherweise aus, nur Ihren runtests.py an der richtigen Stelle zu lokalisieren.

Das Unittest-Modul in Python 2.7+ (das als unittest2 für Python 2.6 und frühere Versionen zurückportiert wird) verfügt jetzt über Test Discovery Built-in Automatisierte Testermittlung: Ihre Benutzeranweisungen können so einfach wie "Python -m Unittest Discover" sein.

45
Carl Meyer

Normalerweise erstelle ich ein Skript "run tests" im Projektverzeichnis (das für das Quellverzeichnis und test üblich ist) und lädt meine "All Tests" -Suite. Dies ist in der Regel ein Boilerplate-Code, sodass ich ihn von Projekt zu Projekt wiederverwenden kann.

run_tests.py:

import unittest
import test.all_tests
testSuite = test.all_tests.create_test_suite()
text_runner = unittest.TextTestRunner().run(testSuite)

test/all_tests.py (von Wie führe ich alle Python-Unit-Tests in einem Verzeichnis aus? )

import glob
import unittest

def create_test_suite():
    test_file_strings = glob.glob('test/test_*.py')
    module_strings = ['test.'+str[5:len(str)-3] for str in test_file_strings]
    suites = [unittest.defaultTestLoader.loadTestsFromName(name) \
              for name in module_strings]
    testSuite = unittest.TestSuite(suites)
    return testSuite

Mit diesem Setup können Sie in Ihren Testmodulen nur include antigravityen. Der Nachteil ist, dass Sie mehr Support-Code benötigen, um einen bestimmten Test auszuführen. Ich führe sie einfach jedes Mal aus.

19
stw_dev

Aus dem Artikel, auf den Sie verlinkt haben:

Erstellen Sie eine test_modulename.py-Datei und Setze deine besten Tests hinein. Schon seit Die Testmodule befinden sich in einem separaten Verzeichnis aus Ihrem Code benötigen Sie möglicherweise um das übergeordnete Verzeichnis Ihres Moduls hinzuzufügen zu deinem PYTHONPATH, um laufen zu lassen Sie:

$ cd /path/to/googlemaps

$ export PYTHONPATH=$PYTHONPATH:/path/to/googlemaps/googlemaps

$ python test/test_googlemaps.py

Schließlich gibt es noch ein beliebteres Gerätetest-Framework für Python (es ist so wichtig!), Nase. Nase vereinfacht und erweitert das eingebaute unittest Framework (es kann zum Beispiel automatisch den test Code finden und Ihren PYTHONPATH für Sie einrichten), aber es ist nicht im Lieferumfang von .__ enthalten. Standard-Python-Verteilung.

Vielleicht solltest du auf Nase schauen, wie es suggeriert?

18
Mark Byers

wenn Sie "python setup.py entwickeln" ausführen, befindet sich das Paket im Pfad. Möglicherweise möchten Sie dies jedoch nicht, weil Sie die Installation Ihres Systems Python infizieren könnten. Deshalb gibt es Tools wie virtualenv und buildout

8
Tom Willis

Ich hatte das gleiche Problem mit einem separaten Gerätetestordner. Von den genannten Vorschlägen füge ich den absoluten Quellpfad zu sys.path hinzu.

Die folgende Lösung hat den Vorteil, dass die Datei test/test_yourmodule.py ausgeführt werden kann, ohne dass zunächst das Testverzeichnis geändert wird:

import sys, os
testdir = os.path.dirname(__file__)
srcdir = '../antigravity'
sys.path.insert(0, os.path.abspath(os.path.join(testdir, srcdir)))

import antigravity
import unittest
8
andpei

Wenn Sie VS-Code verwenden und sich Ihre Tests auf derselben Ebene wie Ihr Projekt befinden, funktioniert das Ausführen und Debuggen Ihres Codes nicht sofort. Sie können die Datei launch.json ändern:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python",
            "type": "python",
            "request": "launch",
            "stopOnEntry": false,
            "pythonPath": "${config:python.pythonPath}",
            "program": "${file}",
            "cwd": "${workspaceRoot}",
            "env": {},
            "envFile": "${workspaceRoot}/.env",
            "debugOptions": [
                "WaitOnAbnormalExit",
                "WaitOnNormalExit",
                "RedirectOutput"
            ]
        }    
    ]
}

Die Schlüsselzeile ist hier envFile

"envFile": "${workspaceRoot}/.env",

Fügen Sie im Stammverzeichnis Ihres Projekts die .env-Datei hinzu

Fügen Sie in Ihrer .env-Datei den Pfad zum Stamm Ihres Projekts hinzu. Dies wird vorübergehend hinzugefügt 

PYTHONPATH = C:\IHR\PYTHON\PROJECT\ROOT_DIRECTORY

pfad zu Ihrem Projekt und Sie können Debug-Unit-Tests von VS Code verwenden

5
Vlad Bezden

Lösung/Beispiel für ein Python-Testmodul

Bei folgender Projektstruktur:

ProjectName
 ├── project_name
 |    ├── models
 |    |    └── thing_1.py
 |    └── __main__.py
 └── test
      ├── models
      |    └── test_thing_1.py
      └── __main__.py

Sie können Ihr Projekt vom Hauptverzeichnis aus mit python project_name ausführen, wodurch ProjectName/project_name/__main__.py aufgerufen wird.


Um Ihre Tests mit python test auszuführen und effektiv ProjectName/test/__main__.py auszuführen, müssen Sie Folgendes tun:

1) Verwandeln Sie Ihr test/models-Verzeichnis in ein Paket, indem Sie eine __init__.py-Datei hinzufügen. Dadurch werden die Testfälle innerhalb des Unterverzeichnisses vom übergeordneten test-Verzeichnis aus zugänglich.

# ProjectName/test/models/__init__.py

from .test_thing_1 import Thing1TestCase        

2) Ändern Sie Ihren Systempfad in test/__main__.py, um das Verzeichnis project_name einzuschließen.

# ProjectName/test/__main__.py

import sys
import unittest

sys.path.append('../project_name')

loader = unittest.TestLoader()
testSuite = loader.discover('test')
testRunner = unittest.TextTestRunner(verbosity=2)
testRunner.run(testSuite)

Jetzt können Sie erfolgreich Dinge aus project_name in Ihre Tests importieren.

# ProjectName/test/models/test_thing_1.py    

import unittest
from project_name.models import Thing1  # this doesn't work without 'sys.path.append' per step 2 above

class Thing1TestCase(unittest.TestCase):

    def test_thing_1_init(self):
        thing_id = 'ABC'
        thing1 = Thing1(thing_id)
        self.assertEqual(thing_id, thing.id)
5
Derek Soike

Verwenden Sie setup.py develop, um Ihr Arbeitsverzeichnis zur installierten Python-Umgebung zu machen, und führen Sie dann die Tests aus.

5
Ned Batchelder

Es ist möglich, einen Wrapper zu verwenden, der ausgewählte oder alle Tests ausführt.

Zum Beispiel:

./run_tests antigravity/*.py

oder um alle Tests rekursiv auszuführen, verwenden Sie globbing (tests/**/*.py) (aktivieren durch shopt -s globstar).

Der Wrapper kann argparse verwenden, um die Argumente wie folgt zu analysieren:

parser = argparse.ArgumentParser()
parser.add_argument('files', nargs='*')

Laden Sie dann alle Tests:

for filename in args.files:
    exec(open(filename).read())

fügen Sie diese dann in Ihre Testsuite ein (mithilfe von inspect):

alltests = unittest.TestSuite()
for name, obj in inspect.getmembers(sys.modules[__name__]):
    if inspect.isclass(obj) and name.startswith("FooTest"):
        alltests.addTest(unittest.makeSuite(obj))

und führe sie aus:

result = unittest.TextTestRunner(verbosity=2).run(alltests)

Überprüfen Sie dieses Beispiel für weitere Details.

Siehe auch: Wie werden alle Python-Komponententests in einem Verzeichnis ausgeführt?

4
kenorb

Ich habe festgestellt, dass, wenn Sie die unittest-Befehlszeilenschnittstelle von Ihrem "src" -Verzeichnis aus ausführen, die Importe ohne Änderung korrekt funktionieren.

python -m unittest discover -s ../test

Wenn Sie das in einer Batch-Datei in Ihrem Projektverzeichnis ablegen möchten, können Sie Folgendes tun:

setlocal & cd src & python -m unittest discover -s ../test
4
Alan L

Folgendes ist meine Projektstruktur:

ProjectFolder:
 - project:
     - __init__.py
     - item.py
 - tests:
     - test_item.py

Ich fand es besser, in der setUp () -Methode zu importieren:

import unittest
import sys    

class ItemTest(unittest.TestCase):

    def setUp(self):
        sys.path.insert(0, "../project")
        from project import item
        # further setup using this import

    def test_item_props(self):
        # do my assertions

if __== "__main__":
    unittest.main()
3
rolika

Wie läuft eigentlich der Test ab?

Ich benutze Python 3.6.2

cd new_project

pytest test/test_antigravity.py

So installieren Sie pytest: Sudo pip install pytest

Ich habe keine Pfadvariable festgelegt und meine Importe schlagen nicht mit derselben "Test" -Projektstruktur fehl.

Ich habe dieses Zeug auskommentiert: if __== '__main__' wie folgt:

test_antigravity.py

import antigravity

class TestAntigravity(unittest.TestCase):

    def test_something(self):

        # ... test stuff here


# if __== '__main__':
# 
#     if __package__ is None:
# 
#         import something
#         sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
#         from .. import antigravity
# 
#     else:
# 
#         from .. import antigravity
# 
#     unittest.main()
3
aliopi

Python 3+

Hinzufügen zu @Pierre

Verwenden Sie die unittest-Verzeichnisstruktur wie folgt:

new_project
├── antigravity
│   ├── __init__.py         # make it a package
│   └── antigravity.py
└── test
    ├── __init__.py         # also make test a package
    └── test_antigravity.py

So führen Sie das Testmodul test_antigravity.py aus:

$ cd new_project
$ python -m unittest test.test_antigravity

Oder eine einzelne TestCase 

$ python -m unittest test.test_antigravity.GravityTestCase

Obligatorisch Den __init__.py nicht vergessen, auch wenn leer, sonst funktioniert es nicht.

2
eusoubrasileiro

Sie können keinen Import aus dem übergeordneten Verzeichnis ohne Voodoo durchführen. Hier ist noch ein anderer Weg, der zumindest mit Python 3.6 funktioniert.

Zuerst muss eine Datei test/context.py mit folgendem Inhalt erstellt werden:

import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

Dann haben Sie folgenden Import in die Datei test/test_antigravity.py:

import unittest
try:
    import context
except ModuleNotFoundError:
    import test.context    
import antigravity

Beachten Sie, dass der Grund für diese Klausel try-except das ist 

  • import test.context schlägt fehl, wenn sie mit "python test_antigravity.py" und ausgeführt wird 
  • import context schlägt fehl, wenn er mit "python -m unittest" aus dem neuen Projektverzeichnis ausgeführt wird.

Mit diesem Trick arbeiten beide. 

Nun können Sie all die Testdateien im Testverzeichnis ausführen mit:

$ pwd
/projects/new_project
$ python -m unittest

oder führen Sie eine individuelle Testdatei aus mit:

$ cd test
$ python test_antigravity

Ok, es ist nicht viel schöner als den Inhalt von context.py in test_antigravity.py zu haben, aber vielleicht ein bisschen. Vorschläge sind willkommen.

2
tjk

Dieses BASH-Skript führt das Testverzeichnis für Python-Tests nur an einer beliebigen Stelle im Dateisystem aus, unabhängig davon, in welchem ​​Arbeitsverzeichnis Sie sich befinden.

Dies ist nützlich, wenn Sie sich im Arbeitsverzeichnis ./src oder ./example befinden und einen schnellen Komponententest benötigen:

#!/bin/bash

this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"

python -m unittest discover -s "$readlink"/test -v

Es ist nicht erforderlich, dass eine test/__init__.py-Datei Ihren Paket-/Speicheraufwand während der Produktion belastet.

1
Egbert S

Wenn Ihr Testverzeichnis mehrere Verzeichnisse enthält, müssen Sie jedem Verzeichnis eine __init__.py - Datei hinzufügen.

/home/johndoe/snakeoil
└── test
    ├── __init__.py        
    └── frontend
        └── __init__.py
        └── test_foo.py
    └── backend
        └── __init__.py
        └── test_bar.py

Führen Sie dann Folgendes aus, um jeden Test gleichzeitig auszuführen:

python -m unittest discover -s /home/johndoe/snakeoil/test -t /home/johndoe/snakeoil

Quelle: python -m unittest -h

  -s START, --start-directory START
                        Directory to start discovery ('.' default)
  -t TOP, --top-level-directory TOP
                        Top level directory of project (defaults to start
                        directory)
0
Qlimax

Auf diese Weise können Sie die Testskripts von jedem beliebigen Ort aus ausführen, ohne über die Befehlszeile mit Systemvariablen herumzuspielen.

Dadurch wird der Hauptprojektordner zum Pfad python hinzugefügt, wobei der Speicherort relativ zum Skript selbst und nicht relativ zum aktuellen Arbeitsverzeichnis gefunden wird.

import sys, os

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))))

Fügen Sie dies zu all Ihren Testskripten hinzu. Dadurch wird der Hauptprojektordner zum Systempfad hinzugefügt, sodass alle Modulimporte, die von dort ausgeführt werden, jetzt ausgeführt werden können. Dabei spielt es keine Rolle, von wo aus Sie die Tests ausführen.

Sie können die Datei project_path_hack natürlich so ändern, dass sie dem Speicherort Ihres Hauptprojektordners entspricht.

0
chasmani

Sie sollten wirklich das Pip-Tool verwenden.

Verwenden Sie pip install -e ., um Ihr Paket im Entwicklungsmodus zu installieren. Dies ist eine sehr gute Praxis, die von pytest empfohlen wird (siehe deren Good Practices-Dokumentation , wo Sie auch zwei zu befolgende Projektlayouts finden).

0
squid

Wenn Sie nach einer reinen Befehlszeilenlösung suchen:

Basierend auf der folgenden Verzeichnisstruktur (verallgemeinert mit einem dedizierten Quellverzeichnis):

new_project/
    src/
        antigravity.py
    test/
        test_antigravity.py

Windows: (in new_project)

$ set PYTHONPATH=%PYTHONPATH%;%cd%\src
$ python -m unittest discover -s test

Siehe diese Frage , wenn Sie diese in einer Batch-for-Schleife verwenden möchten.

Linux: (in new_project)

$ export PYTHONPATH=$PYTHONPATH:$(pwd)/src  [I think - please edit this answer if you are a Linux user and you know this]
$ python -m unittest discover -s test

Mit diesem Ansatz können Sie dem PYTHONPATH bei Bedarf auch weitere Verzeichnisse hinzufügen.

0
pj.dewitte