Uruchamianie unittest z typową strukturą katalogów testowych

Bardzo powszechną strukturą katalogów nawet dla prostego modułu Pythona wydaje się być oddzielenie testów jednostkowych do ich własnego katalogu test:

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

Na przykład zobacz to Python project howto .

Moje pytanie brzmi po prostu jaki jest zwykły sposób przeprowadzania testów? podejrzewam, że jest to oczywiste dla wszystkich oprócz mnie, ale nie możesz po prostu uruchomić python test_antigravity.py z katalogu testowego, ponieważ jego import antigravity nie powiedzie się, ponieważ moduł nie znajduje się na ścieżce.

I know I może zmodyfikować PYTHONPATH i inne sztuczki związane ze ścieżką wyszukiwania, ale nie mogę uwierzyć, że jest to najprostszy sposób - jest w porządku, jeśli jesteś programistą, ale nie realistycznie oczekiwać, że użytkownicy będą używać, jeśli chcą tylko sprawdzić, czy testy przechodzą.

Inną alternatywą jest po prostu skopiowanie pliku testowego do innego katalogu, ale wydaje się to nieco głupie i pomija sens posiadania ich w osobnym katalogu na początek.

Więc, gdybyś właśnie ściągnął źródło do mojego nowego projektu jak przeprowadziłbyś testy jednostkowe? Wolałbym odpowiedź, która pozwoliłaby mi powiedzieć moim użytkownikom: "aby uruchomić testy jednostkowe do X."

Author: Scott Griffiths, 2009-12-13

16 answers

Moim zdaniem najlepszym rozwiązaniem jest użycie unittest interfejs wiersza poleceń, który doda katalog do sys.path, więc nie musisz (robione w klasie TestLoader).

Na przykład dla struktury katalogów takiej jak ta:

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

Możesz po prostu uruchomić:

$ cd new_project
$ python -m unittest test_antigravity

Dla struktury katalogów takiej jak twoja:

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

I w modułach testowych wewnątrz pakietu test, można zaimportować pakiet antigravity i jego moduły jako Zwykle:

# 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

Uruchomienie pojedynczego modułu testowego:

Aby uruchomić pojedynczy moduł testowy, w tym przypadku test_antigravity.py:

$ cd new_project
$ python -m unittest test.test_antigravity

Po prostu odwołaj się do modułu testowego w ten sam sposób, w jaki go importujesz.

Uruchamianie pojedynczego przypadku testowego lub metody badania:

Możesz również uruchomić pojedynczą TestCase lub pojedynczą metodę testową:

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

Uruchamianie wszystkich testów:

Możesz również użyć test discovery, który odkryje i uruchomi wszystkie testy dla Ciebie muszą być modułami lub pakietami o nazwie test*.py (można je zmienić za pomocą znacznika -p, --pattern):

$ cd new_project
$ python -m unittest discover

Spowoduje uruchomienie wszystkich test*.py modułów wewnątrz test pakietu.

 473
Author: Pierre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-23 08:49:11

Najprostszym rozwiązaniem dla użytkowników jest dostarczenie skryptu wykonywalnego (runtests.py lub jakiegoś podobnego), który uruchamia niezbędne środowisko testowe, włączając w to, w razie potrzeby, dodanie katalogu głównego projektu do sys./ align = "left" / Nie wymaga to od użytkowników ustawiania zmiennych środowiskowych, coś takiego działa dobrze w skrypcie bootstrap:

import sys, os

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

Wtedy instrukcje dla użytkowników mogą być tak proste ,jak "python runtests.py".

Oczywiście, jeśli ścieżka, której potrzebujesz naprawdę jest os.path.dirname(__file__), Python zawsze umieszcza katalog aktualnie uruchomionego skryptu na początku sys.path, więc w zależności od struktury katalogów może być wszystko, co jest potrzebne, po prostu zlokalizowanie runtests.py we właściwym miejscu.

Ponadto moduł unittest w Pythonie 2.7+ (który jest backportowany jako unittest2 dla Pythona 2.6 i wcześniejszych) ma teraz wbudowane wykrywanie testów , więc nos nie jest już potrzebny, jeśli chcesz zautomatyzować test discovery: instrukcje użytkownika mogą być tak proste jak "python-m unittest discover".

 43
Author: Carl Meyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-23 05:15:30

Zazwyczaj tworzę skrypt " uruchom testy "w katalogu projektu (tym, który jest wspólny zarówno dla katalogu źródłowego, jak i test), który ładuje mój pakiet" wszystkie testy". Zazwyczaj jest to kod boilerplate, więc mogę go ponownie użyć od projektu do projektu.

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 (from Jak uruchomić wszystkie testy jednostkowe Pythona w katalogu?)

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

Dzięki tej konfiguracji możesz rzeczywiście po prostu include antigravity w swoich modułach testowych. Minusem jest to, że potrzebujesz więcej kod wsparcia do wykonania konkretnego testu... Sprawdzam je za każdym razem.

 18
Author: stw_dev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:03:02

Z artykułu, do którego podlinkowałeś:

Create a test_modulename.py plik i umieść w nim swoje najmocniejsze testy. Od Moduły testowe znajdują się w oddzielnym katalog z twojego kodu, możesz potrzebować aby dodać Katalog nadrzędny modułu do twojego PYTHONPATH, aby uruchomić them:

$ cd /path/to/googlemaps

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

$ python test/test_googlemaps.py

Wreszcie jest jeszcze jeden popularny unit testing framework for Python (to takie ważne!), nos. nos pomaga uprościć i rozszerzyć wbudowany unittest framework (może, na przykład, automagicznie Znajdź swój test kod i skonfiguruj PYTHONPATH dla ty), ale nie jest on dołączony do standardowa Dystrybucja Pythona.

Może powinieneś spojrzeć na nos Jak to sugeruje?

 17
Author: Mark Byers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-13 16:25:43

Jeśli uruchomisz "python setup.py develop" wtedy pakiet będzie na ścieżce. Ale możesz nie chcieć tego robić, ponieważ możesz zainfekować instalację Pythona systemowego, dlatego istnieją narzędzia takie jak virtualenvi buildout.

 6
Author: Tom Willis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-13 16:27:00

Miałem ten sam problem, z oddzielnym folderem testów jednostkowych. Ze wspomnianych sugestii dodaję absolutną ścieżkę źródłową do sys.path.

Zaletą następującego rozwiązania jest to, że można uruchomić plik {[2] } bez zmiany na początku do katalogu testowego:

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
 6
Author: andpei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-25 08:41:44

Użyj setup.py develop, aby twój katalog roboczy stał się częścią zainstalowanego środowiska Pythona, a następnie uruchom testy.

 4
Author: Ned Batchelder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-13 16:24:53

Jeśli używasz VS Code, a twoje testy znajdują się na tym samym poziomie co twój projekt, uruchamianie i debugowanie kodu nie działa po wyjęciu z pudełka. Możesz zmienić swój start.plik json:

{
    "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"
            ]
        }    
    ]
}

Kluczowy wiersz to envFile

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

W korzeniu twojego projektu Dodaj .plik env

Wewnątrz twojego .plik env Dodaj ścieżkę do katalogu głównego projektu. To tymczasowo doda

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

Ścieżka do twojego projektu i będziesz mógł użyć testów jednostkowych z VS Code

 4
Author: Vlad Bezden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-28 00:38:45

Rozwiązanie / przykład dla modułu unittest Pythona

Biorąc pod uwagę następującą strukturę projektu:

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

Możesz uruchomić swój projekt z katalogu głównego za pomocą python project_name, który wywołuje ProjectName/project_name/__main__.py.


Aby przeprowadzić testy z python test, efektywnie uruchamiając ProjectName/test/__main__.py, musisz wykonać następujące czynności:

1) Zmień swój katalog test/models W pakiet, dodając plik __init__.py. To sprawia, że przypadki testowe w podkatalogu są dostępne z poziomu rodzica test katalog.

# ProjectName/test/models/__init__.py

from .test_thing_1 import Thing1TestCase        

2) zmodyfikuj ścieżkę systemową w test/__main__.py, aby dołączyć do katalogu project_name.

# 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)

Teraz możesz z powodzeniem importować rzeczy z project_name w swoich testach.

# 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)
 3
Author: Derek Soike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-28 23:45:13

Oto moja struktura projektu:

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

Uznałem, że lepiej zaimportować w metodzie setUp ():

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 __name__ == "__main__":
    unittest.main()
 2
Author: rolika,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-25 14:01:44

Jak zwykle przeprowadza się testy

Używam Pythona 3.6.2

cd new_project

pytest test/test_antigravity.py

Aby zainstalować : sudo pip install pytest

Nie ustawiłem żadnej zmiennej path i mój Import nie zawodzi z tą samą" testową " strukturą projektu.

Skomentowałem to: if __name__ == '__main__' tak:

Test_antigravity.py

import antigravity

class TestAntigravity(unittest.TestCase):

    def test_something(self):

        # ... test stuff here


# if __name__ == '__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()
 2
Author: aliopi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-26 21:55:33

Zauważyłem, że jeśli uruchomisz interfejs wiersza poleceń unittest z katalogu "src", import działa poprawnie bez modyfikacji.

python -m unittest discover -s ../test

Jeśli chcesz umieścić to w pliku wsadowym w katalogu projektu, możesz to zrobić:

setlocal & cd src & python -m unittest discover -s ../test
 2
Author: Alan L,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-07 23:13:39

Możliwe jest użycie wrappera, który uruchamia wybrane lub wszystkie testy.

Na przykład:

./run_tests antigravity/*.py

Lub aby uruchomić wszystkie testy rekurencyjnie użyj globbing (tests/**/*.py) (enable by shopt -s globstar).

Wrapper może w zasadzie używać argparse do parsowania argumentów takich jak:

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

Następnie załaduj wszystkie testy:

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

Następnie dodaj je do swojego zestawu testów (używając 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))

I uruchom je:

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

Sprawdź ten przykład więcej szczegóły.

Zobacz także: Jak uruchomić wszystkie testy jednostkowe Pythona w katalogu?

 2
Author: kenorb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-30 13:13:06

Ten skrypt BASH uruchomi testowy katalog unittest Pythona z dowolnego miejsca w systemie plików, bez względu na to, w jakim katalogu roboczym się znajdujesz.

Jest to przydatne podczas pobytu w katalogu roboczym ./src lub ./example i potrzebujesz szybkiego testu jednostkowego:

#!/bin/bash

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

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

Nie ma potrzeby, aby plik test/__init__.py obciążał Twój Pakiet / narzut pamięci podczas produkcji.

 0
Author: Egbert S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-13 00:50:04

Python 3 +

dodawanie do @ Pierre

Używanie unittest struktury katalogów w ten sposób:

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

Aby uruchomić moduł testowy test_antigravity.py:

$ cd new_project
$ python -m unittest test.test_antigravity

Lub pojedynczy TestCase

$ python -m unittest test.test_antigravity.GravityTestCase

Obowiązkowe nie zapomnij __init__.py nawet jeśli puste inaczej nie zadziała.

 0
Author: eusoubrasileiro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-08 15:12:19

Naprawdę powinieneś użyć narzędzia pip.

Użyj pip install -e, aby zainstalować pakiet w trybie deweloperskim. To bardzo dobra praktyka.

W podanym poniżej adresie URL Ref podano 2 klasyczny układ projektu (z testem), możesz śledzić dowolny z nich.

Ref :

 -3
Author: squid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:40