UnitTest Framework - Szybki przewodnik
Testowanie jednostkowe to metoda testowania oprogramowania, za pomocą której poszczególne jednostki kodu źródłowego, takie jak funkcje, metody i klasy, są testowane w celu określenia, czy nadają się do użycia. Intuicyjnie można postrzegać jednostkę jako najmniejszą testowalną część aplikacji. Testy jednostkowe to krótkie fragmenty kodu tworzone przez programistów podczas procesu programowania. Stanowi podstawę do testowania komponentów.
Testowanie jednostkowe można przeprowadzić na dwa sposoby -
Testowanie ręczne | Testowanie automatyczne |
---|---|
Ręczne wykonywanie przypadków testowych bez wsparcia narzędziowego nazywane jest testowaniem ręcznym.
|
Korzystanie ze wsparcia narzędziowego i wykonywanie przypadków testowych za pomocą narzędzia do automatyzacji jest znane jako testowanie automatyzacji.
|
JUnit to platforma do testów jednostkowych dla języka programowania Java. JUnit odegrał ważną rolę w rozwoju programowania opartego na testach i jest jednym z rodziny frameworków do testów jednostkowych, zwanych łącznie xUnit, które wywodzą się z JUnit. Możesz dowiedzieć się samouczka JUnit tutaj.
Struktura testów jednostkowych Pythona, czasami nazywana „PyUnit”, jest wersją JUnit w języku Python opracowaną przez Kenta Becka i Ericha Gamma. PyUnit stanowi część biblioteki standardowej języka Python od wersji 2.1 języka Python.
Struktura testów jednostkowych Pythona obsługuje automatyzację testów, udostępnianie kodu konfiguracji i zamykania testów, agregację testów w kolekcje oraz niezależność testów od struktury raportowania. Moduł unittest udostępnia klasy, które ułatwiają obsługę tych cech w zestawie testów.
Ten samouczek został przygotowany dla początkujących, aby pomóc im zrozumieć podstawowe funkcje platformy testowej Python. Po ukończeniu tego samouczka osiągniesz średni poziom wiedzy w zakresie korzystania z platformy testowej Python, z której możesz przejść na kolejne poziomy.
Powinieneś mieć rozsądną wiedzę w zakresie tworzenia oprogramowania w języku Python. Nasz samouczek Pythona jest dobrym miejscem do rozpoczęcia nauki języka Python. Pożądana jest również znajomość podstaw testowania oprogramowania.
Konfiguracja środowiska
Klasy potrzebne do napisania testów znajdują się w module „unittest”. Jeśli używasz starszych wersji Pythona (wcześniejszych niż Python 2.1), moduł można pobrać zhttp://pyunit.sourceforge.net/. Jednak moduł unittest jest teraz częścią standardowej dystrybucji Pythona; dlatego nie wymaga oddzielnej instalacji.
„unittest” obsługuje automatyzację testów, udostępnianie kodu konfiguracji i zamykania testów, agregację testów w kolekcje oraz niezależność testów od struktury raportowania.
Moduł unittest udostępnia klasy, które ułatwiają obsługę tych cech w zestawie testów.
Aby to osiągnąć, unittest wspiera następujące ważne koncepcje -
test fixture- To oznacza przygotowanie potrzebne do wykonania jednego lub więcej testów i wszelkich powiązanych działań porządkowych. Może to obejmować na przykład tworzenie tymczasowych lub proxy baz danych, katalogów lub uruchamianie procesu serwera.
test case- To najmniejsza jednostka testowa. Sprawdza konkretną odpowiedź na określony zestaw danych wejściowych. unittest dostarcza klasę bazową,TestCase, które można wykorzystać do tworzenia nowych przypadków testowych.
test suite- To jest zbiór przypadków testowych, zestawów testów lub obu. Służy do agregowania testów, które powinny być wykonywane razem. Zestawy testów są implementowane przez klasę TestSuite.
test runner- Jest to komponent, który organizuje wykonanie testów i dostarcza wyniki użytkownikowi. Biegacz może użyć interfejsu graficznego, interfejsu tekstowego lub zwrócić specjalną wartość, aby wskazać wyniki wykonywania testów.
Tworzenie testu jednostkowego
Poniższe kroki obejmują napisanie prostego testu jednostkowego -
Step 1 - Zaimportuj moduł unittest do swojego programu.
Step 2- Zdefiniuj funkcję do przetestowania. W poniższym przykładzie funkcja add () ma zostać poddana testowi.
Step 3 - Utwórz przypadek testowy przez podklasę unittest.TestCase.
Step 4- Zdefiniuj test jako metodę wewnątrz klasy. Nazwa metody musi zaczynać się od „test”.
Step 5- Każdy test wywołuje funkcję assert klasy TestCase. Istnieje wiele typów potwierdzeń. Poniższy przykład wywołuje funkcję assertEquals ().
Step 6 - Funkcja assertEquals () porównuje wynik funkcji add () z argumentem arg2 i zgłasza błąd assertionError, jeśli porównanie się nie powiedzie.
Step 7 - Na koniec wywołaj metodę main () z modułu unittest.
import unittest
def add(x,y):
return x + y
class SimpleTest(unittest.TestCase):
def testadd1(self):
self.assertEquals(add(4,5),9)
if __name__ == '__main__':
unittest.main()
Step 8 - Uruchom powyższy skrypt z wiersza poleceń.
C:\Python27>python SimpleTest.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Step 9 - Następujące trzy mogą być możliwymi wynikami testu -
Sr.No | Wiadomość i opis |
---|---|
1 | OK Test przeszedł pomyślnie. Na konsoli wyświetla się „A”. |
2 | FAIL Test nie przechodzi i zgłasza wyjątek AssertionError. Na konsoli wyświetla się „F”. |
3 | ERROR Test zgłasza wyjątek inny niż AssertionError. Na konsoli wyświetla się „E”. |
Te wyniki są wyświetlane na konsoli odpowiednio za pomocą znaków „.”, „F” i „E”.
Interfejs linii komend
Moduł unittest może być używany z wiersza poleceń do uruchamiania pojedynczych lub wielu testów.
python -m unittest test1
python -m unittest test_module.TestClass
python -m unittest test_module.TestClass.test_method
unittest obsługuje następujące opcje wiersza poleceń. Aby uzyskać listę wszystkich opcji wiersza polecenia, użyj następującego polecenia -
Python –m unittest -h
Sr.No | Opcja i opis |
---|---|
1 | -h, --help Pokaż tę wiadomość |
2 | v, --verbose Gadatliwe wyjście |
3 | -q, --quiet Minimalna wydajność |
4 | -f, --failfast Zatrzymaj się przy pierwszej awarii |
5 | -c, --catch Złap Control-C i wyświetl wyniki |
6 | -b, --buffer Stdout bufora i stderr podczas przebiegów testowych |
W tym rozdziale omówiono klasy i metody zdefiniowane w module unittest. W tym module jest pięć głównych klas.
Klasa TestCase
Obiekt tej klasy reprezentuje najmniejszą możliwą do przetestowania jednostkę. Przechowuje procedury testowe i zapewnia haczyki do przygotowania każdej procedury i późniejszego czyszczenia.
W klasie TestCase zdefiniowano następujące metody -
Sr.No | Metoda i opis |
---|---|
1 | setUp() Metoda wywołana w celu przygotowania osprzętu testowego. Jest to wywoływane bezpośrednio przed wywołaniem metody testowej |
2 | tearDown() Metoda wywoływana natychmiast po wywołaniu metody testowej i zapisaniu wyniku. Jest to wywoływane, nawet jeśli metoda testowa zgłosiła wyjątek, |
3 | setUpClass() Metoda klasowa wywoływana przed testami w przebiegu pojedynczej klasy. |
4 | tearDownClass() Metoda klasowa wywoływana po wykonaniu testów w klasie indywidualnej. |
5 | run(result = None) Uruchom test, zbierając wynik do obiektu wyniku testu przekazanego jako wynik . |
6 | skipTest(reason) Wywołanie tego podczas metody testowej lub setUp () pomija bieżący test. |
7 | debug() Uruchom test bez zbierania wyniku. |
8 | shortDescription() Zwraca jednowierszowy opis testu. |
Oprawy
W klasie TestCase może być wiele testów. Te metody testowe mogą wymagać zainicjowania połączenia z bazą danych, plików tymczasowych lub innych zasobów. Nazywa się to urządzeniami. TestCase zawiera specjalny punkt zaczepienia do konfigurowania i czyszczenia wszelkich urządzeń potrzebnych do testów. Aby skonfigurować urządzenia, nadpisanie setUp (). Aby wyczyścić, zastąp tearDown ().
W poniższym przykładzie dwa testy są napisane w klasie TestCase. Sprawdzają wynik dodawania i odejmowania dwóch wartości. Metoda setup () inicjuje argumenty w oparciu o shortDescription () każdego testu. teardown () zostanie wykonana na końcu każdego testu.
import unittest
class simpleTest2(unittest.TestCase):
def setUp(self):
self.a = 10
self.b = 20
name = self.shortDescription()
if name == "Add":
self.a = 10
self.b = 20
print name, self.a, self.b
if name == "sub":
self.a = 50
self.b = 60
print name, self.a, self.b
def tearDown(self):
print '\nend of test',self.shortDescription()
def testadd(self):
"""Add"""
result = self.a+self.b
self.assertTrue(result == 100)
def testsub(self):
"""sub"""
result = self.a-self.b
self.assertTrue(result == -10)
if __name__ == '__main__':
unittest.main()
Uruchom powyższy kod z wiersza poleceń. Daje następujący wynik -
C:\Python27>python test2.py
Add 10 20
F
end of test Add
sub 50 60
end of test sub
.
================================================================
FAIL: testadd (__main__.simpleTest2)
Add
----------------------------------------------------------------------
Traceback (most recent call last):
File "test2.py", line 21, in testadd
self.assertTrue(result == 100)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 2 tests in 0.015s
FAILED (failures = 1)
Urządzenie klasowe
Klasa TestCase ma metodę setUpClass (), którą można przesłonić w celu wykonania przed wykonaniem poszczególnych testów w klasie TestCase. Podobnie, metoda tearDownClass () zostanie wykonana po wykonaniu wszystkich testów w klasie. Obie metody są metodami klasowymi. Dlatego muszą być ozdobione dyrektywą @classmethod.
Poniższy przykład demonstruje użycie tych metod klas -
import unittest
class TestFixtures(unittest.TestCase):
@classmethod
def setUpClass(cls):
print 'called once before any tests in class'
@classmethod
def tearDownClass(cls):
print '\ncalled once after all tests in class'
def setUp(self):
self.a = 10
self.b = 20
name = self.shortDescription()
print '\n',name
def tearDown(self):
print '\nend of test',self.shortDescription()
def test1(self):
"""One"""
result = self.a+self.b
self.assertTrue(True)
def test2(self):
"""Two"""
result = self.a-self.b
self.assertTrue(False)
if __name__ == '__main__':
unittest.main()
Klasa TestSuite
Struktura testowa Pythona zapewnia przydatny mechanizm, dzięki któremu instancje przypadków testowych mogą być grupowane razem według testowanych funkcji. Mechanizm ten udostępnia klasa TestSuite w module unittest.
Poniższe kroki obejmują tworzenie i uruchamianie zestawu testów.
Step 1 - Utwórz instancję klasy TestSuite.
suite = unittest.TestSuite()
Step 2 - Dodaj testy wewnątrz klasy TestCase w zestawie.
suite.addTest(testcase class)
Step 3 - Możesz także użyć metody makeSuite (), aby dodać testy z klasy
suite = unittest.makeSuite(test case class)
Step 4 - W pakiecie można również dodać testy indywidualne.
suite.addTest(testcaseclass(""testmethod")
Step 5 - Utwórz obiekt klasy TestTestRunner.
runner = unittest.TextTestRunner()
Step 6 - Wywołaj metodę run (), aby uruchomić wszystkie testy w zestawie
runner.run (suite)
W klasie TestSuite zdefiniowano następujące metody -
Sr.No | Metoda i opis |
---|---|
1 | addTest() Dodaje metodę testową w zestawie testów. |
2 | addTests() Dodaje testy z wielu klas TestCase. |
3 | run() Uruchamia testy skojarzone z tym zestawem, zbierając wynik do obiektu wyniku testu |
4 | debug() Uruchamia testy skojarzone z tym zestawem bez zbierania wyniku. |
5 | countTestCases() Zwraca liczbę testów reprezentowanych przez ten obiekt testowy |
Poniższy przykład pokazuje, jak używać klasy TestSuite -
import unittest
class suiteTest(unittest.TestCase):
def setUp(self):
self.a = 10
self.b = 20
def testadd(self):
"""Add"""
result = self.a+self.b
self.assertTrue(result == 100)
def testsub(self):
"""sub"""
result = self.a-self.b
self.assertTrue(result == -10)
def suite():
suite = unittest.TestSuite()
## suite.addTest (simpleTest3("testadd"))
## suite.addTest (simpleTest3("testsub"))
suite.addTest(unittest.makeSuite(simpleTest3))
return suite
if __name__ == '__main__':
runner = unittest.TextTestRunner()
test_suite = suite()
runner.run (test_suite)
Możesz poeksperymentować z metodą addTest (), odkomentowując wiersze i instrukcję komentarza z metodą makeSuite ().
Klasa TestLoader
Pakiet unittest ma klasę TestLoader, która służy do tworzenia zestawów testów z klas i modułów. Domyślnie instancja unittest.defaultTestLoader jest tworzona automatycznie po wywołaniu metody unittest.main (0. Wystąpienie jawne umożliwia jednak dostosowanie niektórych właściwości.
W poniższym kodzie testy z dwóch klas są zbierane na liście przy użyciu obiektu TestLoader.
import unittest
testList = [Test1, Test2]
testLoad = unittest.TestLoader()
TestList = []
for testCase in testList:
testSuite = testLoad.loadTestsFromTestCase(testCase)
TestList.append(testSuite)
newSuite = unittest.TestSuite(TestList)
runner = unittest.TextTestRunner()
runner.run(newSuite)
Poniższa tabela przedstawia listę metod w klasie TestLoader -
S.Nr | Metoda i opis |
---|---|
1 | loadTestsFromTestCase() Zwraca zestaw wszystkich przypadków testowych zawartych w klasie TestCase |
2 | loadTestsFromModule() Zwraca zestaw wszystkich przypadków testowych zawartych w danym module. |
3 | loadTestsFromName() Zwraca zestaw wszystkich przypadków testowych, podając specyfikator ciągu. |
4 | discover() Znajdź wszystkie moduły testowe, przechodząc do podkatalogów z określonego katalogu startowego i zwróć obiekt TestSuite |
Klasa TestResult
Ta klasa służy do kompilowania informacji o testach, które zakończyły się powodzeniem, i testach, które zakończyły się niepowodzeniem. Obiekt TestResult przechowuje wyniki zestawu testów. Instancja TestResult jest zwracana przez metodę TestRunner.run ().
Instancje TestResult mają następujące atrybuty -
Sr.No | Atrybut i opis |
---|---|
1 | Errors Lista zawierająca 2 krotki instancji TestCase i ciągi przechowujące sformatowane dane śledzenia. Każda krotka reprezentuje test, który zgłosił nieoczekiwany wyjątek. |
2 | Failures Lista zawierająca 2 krotki instancji TestCase i ciągi przechowujące sformatowane dane śledzenia. Każda krotka reprezentuje test, w którym błąd został jawnie zasygnalizowany przy użyciu metod TestCase.assert * (). |
3 | Skipped Lista zawierająca 2 krotki instancji TestCase i ciągi zawierające przyczynę pominięcia testu. |
4 | wasSuccessful() Zwróć True, jeśli wszystkie dotychczas wykonane testy zakończyły się pomyślnie, w przeciwnym razie zwraca False. |
5 | stop() Tę metodę można wywołać w celu zasygnalizowania, że zestaw uruchamianych testów powinien zostać przerwany. |
6 | startTestRun() Wywoływane raz przed wykonaniem jakichkolwiek testów. |
7 | stopTestRun() Wywoływane raz po wykonaniu wszystkich testów. |
8 | testsRun Łączna liczba przeprowadzonych dotychczas testów. |
9 | Buffer Jeśli ustawione na true, sys.stdout i sys.stderr będzie buforowana pomiędzy wywołaniami startTest () i stopTest (). |
Poniższy kod wykonuje zestaw testów -
if __name__ == '__main__':
runner = unittest.TextTestRunner()
test_suite = suite()
result = runner.run (test_suite)
print "---- START OF TEST RESULTS"
print result
print "result::errors"
print result.errors
print "result::failures"
print result.failures
print "result::skipped"
print result.skipped
print "result::successful"
print result.wasSuccessful()
print "result::test-run"
print result.testsRun
print "---- END OF TEST RESULTS"
Kod po wykonaniu wyświetla następujące dane wyjściowe -
---- START OF TEST RESULTS
<unittest.runner.TextTestResult run = 2 errors = 0 failures = 1>
result::errors
[]
result::failures
[(<__main__.suiteTest testMethod = testadd>, 'Traceback (most recent call last):\n
File "test3.py", line 10, in testadd\n
self.assertTrue(result == 100)\nAssert
ionError: False is not true\n')]
result::skipped
[]
result::successful
False
result::test-run
2
---- END OF TEST RESULTS
Struktura testowa Pythona używa wbudowanej w Pythonie funkcji assert (), która testuje określony warunek. Jeśli asercja się nie powiedzie, zostanie zgłoszony AssertionError. Struktura testowa zidentyfikuje test jako niepowodzenie. Inne wyjątki są traktowane jako błąd.
Poniższe trzy zestawy funkcji asercji są zdefiniowane w module unittest -
- Podstawowe potwierdzenia logiczne
- Oświadczenia porównawcze
- Potwierdzenia dla kolekcji
Podstawowe funkcje assert oceniają, czy wynik operacji jest True, czy False. Wszystkie metody asercji akceptują plikmsg argument, który, jeśli jest określony, jest używany jako komunikat o błędzie w przypadku niepowodzenia.
Sr.No | Metoda i opis |
---|---|
1 | assertEqual(arg1, arg2, msg = None) Sprawdź, czy arg1 i arg2 są równe. Jeśli wartości nie są równe, test zakończy się niepowodzeniem. |
2 | assertNotEqual(arg1, arg2, msg = None) Sprawdź, czy argumenty arg1 i arg2 nie są równe. Jeśli wartości są równe, test zakończy się niepowodzeniem. |
3 | assertTrue(expr, msg = None) Sprawdź, czy wyrażenie jest prawdziwe. Jeśli nie, test kończy się niepowodzeniem |
4 | assertFalse(expr, msg = None) Sprawdź, czy wyrażenie jest fałszywe. Jeśli prawda, test kończy się niepowodzeniem |
5 | assertIs(arg1, arg2, msg = None) Sprawdź, czy argumenty arg1 i arg2 zwracają się do tego samego obiektu. |
6 | assertIsNot(arg1, arg2, msg = None) Sprawdź, czy argumenty arg1 i arg2 nie są przeliczane na ten sam obiekt. |
7 | assertIsNone(expr, msg = None) Sprawdź, czy wyrażenie ma wartość Brak. Jeśli nie, test kończy się niepowodzeniem |
8 | assertIsNotNone(expr, msg = None) Sprawdź, czy wyrażenie nie jest None. Jeśli brak, test kończy się niepowodzeniem |
9 | assertIn(arg1, arg2, msg = None) Sprawdź, czy arg1 znajduje się w arg2 . |
10 | assertNotIn(arg1, arg2, msg = None) Sprawdź, czy arg1 nie znajduje się w arg2 . |
11 | assertIsInstance(obj, cls, msg = None) Sprawdź, czy obj jest instancją cls |
12 | assertNotIsInstance(obj, cls, msg = None) Sprawdź, czy obj nie jest instancją cls |
Niektóre z powyższych funkcji asercji są zaimplementowane w następującym kodzie -
import unittest
class SimpleTest(unittest.TestCase):
def test1(self):
self.assertEqual(4 + 5,9)
def test2(self):
self.assertNotEqual(5 * 2,10)
def test3(self):
self.assertTrue(4 + 5 == 9,"The result is False")
def test4(self):
self.assertTrue(4 + 5 == 10,"assertion fails")
def test5(self):
self.assertIn(3,[1,2,3])
def test6(self):
self.assertNotIn(3, range(5))
if __name__ == '__main__':
unittest.main()
Po uruchomieniu powyższego skryptu testy test2, test4 i test6 pokażą błąd, a inne działają pomyślnie.
FAIL: test2 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python27\SimpleTest.py", line 9, in test2
self.assertNotEqual(5*2,10)
AssertionError: 10 == 10
FAIL: test4 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python27\SimpleTest.py", line 13, in test4
self.assertTrue(4+5==10,"assertion fails")
AssertionError: assertion fails
FAIL: test6 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python27\SimpleTest.py", line 17, in test6
self.assertNotIn(3, range(5))
AssertionError: 3 unexpectedly found in [0, 1, 2, 3, 4]
----------------------------------------------------------------------
Ran 6 tests in 0.001s
FAILED (failures = 3)
Drugi zestaw funkcji asercji to comparative asserts −
assertAlmostEqual (pierwsza, druga, miejsca = 7, msg = brak, delta = brak)
Sprawdź, czy pierwsza i druga są w przybliżeniu (lub nie w przybliżeniu) równe, obliczając różnicę, zaokrąglając do podanej liczby miejsc dziesiętnych (domyślnie 7),
assertNotAlmostEqual (pierwsza, druga, miejsca, msg, delta)
Sprawdź, czy pierwsza i druga nie są w przybliżeniu równe, obliczając różnicę, zaokrąglając do podanej liczby miejsc dziesiętnych (domyślnie 7) i porównując do zera.
W obu powyższych funkcjach, jeśli delta jest podawana zamiast miejsc, wówczas różnica między pierwszą a drugą musi być mniejsza lub równa (lub większa) delta.
Podanie zarówno delta, jak i miejsc wywołuje błąd TypeError.
assertGreater (pierwsza, druga, msg = brak)
Sprawdź, czy pierwsza jest większa niż druga, w zależności od nazwy metody. Jeśli nie, test zakończy się niepowodzeniem.
assertGreaterEqual (pierwsza, druga, msg = brak)
Sprawdź, czy pierwsza jest większa lub równa drugiej, w zależności od nazwy metody. Jeśli nie, test zakończy się niepowodzeniem
assertLess (pierwsza, druga, msg = brak)
Sprawdź, czy pierwsza jest krótsza niż druga, w zależności od nazwy metody. Jeśli nie, test zakończy się niepowodzeniem
assertLessEqual (pierwsza, druga, msg = brak)
Sprawdź, czy pierwsza jest mniejsza lub równa drugiej, w zależności od nazwy metody. Jeśli nie, test zakończy się niepowodzeniem.
assertRegexpMatches (tekst, wyrażenie regularne, msg = brak)
Sprawdź, czy wyszukiwanie wyrażenia regularnego pasuje do tekstu. W przypadku niepowodzenia komunikat o błędzie będzie zawierał wzór i tekst. regexp może być obiektem wyrażenia regularnego lub napisem zawierającym wyrażenie regularne odpowiednie do użycia przezre.search().
assertNotRegexpMatches (tekst, wyrażenie regularne, msg = brak)
Sprawdza, czy wyszukiwanie wyrażenia regularnego nie pasuje do tekstu . Niepowodzenie z komunikatem o błędzie zawierającym wzorzec i pasującą część tekstu . regexp może być obiektem wyrażenia regularnego lub napisem zawierającym wyrażenie regularne odpowiednie do użycia przezre.search().
Funkcje asercji są zaimplementowane w następującym przykładzie -
import unittest
import math
import re
class SimpleTest(unittest.TestCase):
def test1(self):
self.assertAlmostEqual(22.0/7,3.14)
def test2(self):
self.assertNotAlmostEqual(10.0/3,3)
def test3(self):
self.assertGreater(math.pi,3)
def test4(self):
self.assertNotRegexpMatches("Tutorials Point (I) Private Limited","Point")
if __name__ == '__main__':
unittest.main()
Powyższy skrypt zgłasza test1 i test4 jako błąd. W teście 1 podział 22/7 nie mieści się w granicach 7 miejsc po przecinku 3,14. Podobnie, ponieważ drugi argument pasuje do tekstu w pierwszym argumencie, test4 daje w wyniku AssertionError.
=====================================================FAIL: test1 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "asserttest.py", line 7, in test1
self.assertAlmostEqual(22.0/7,3.14)
AssertionError: 3.142857142857143 != 3.14 within 7 places
================================================================
FAIL: test4 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "asserttest.py", line 13, in test4
self.assertNotRegexpMatches("Tutorials Point (I) Private Limited","Point")
AssertionError: Regexp matched: 'Point' matches 'Point' in 'Tutorials Point (I)
Private Limited'
----------------------------------------------------------------------
Ran 4 tests in 0.001s
FAILED (failures = 2)
Zgłoś się do kolekcji
Ten zestaw funkcji assert ma być używany z typami danych kolekcji w Pythonie, takimi jak List, Tuple, Dictionary i Set.
Sr.No | Metoda i opis |
---|---|
1 | assertListEqual (list1, list2, msg = None) Sprawdza, czy dwie listy są równe. Jeśli nie, tworzony jest komunikat o błędzie, który pokazuje tylko różnice między nimi. |
2 | assertTupleEqual (tuple1, tuple2, msg = None) Testuje, że dwie krotki są równe. Jeśli nie, tworzony jest komunikat o błędzie, który pokazuje tylko różnice między nimi. |
3 | assertSetEqual (set1, set2, msg = None) Testy, że dwa zestawy są równe. Jeśli nie, tworzony jest komunikat o błędzie, który zawiera listę różnic między zestawami. |
4 | assertDictEqual (expected, actual, msg = None) Sprawdź, czy dwa słowniki są równe. Jeśli nie, tworzony jest komunikat o błędzie, który pokazuje różnice w słownikach. |
Poniższy przykład implementuje powyższe metody -
import unittest
class SimpleTest(unittest.TestCase):
def test1(self):
self.assertListEqual([2,3,4], [1,2,3,4,5])
def test2(self):
self.assertTupleEqual((1*2,2*2,3*2), (2,4,6))
def test3(self):
self.assertDictEqual({1:11,2:22},{3:33,2:22,1:11})
if __name__ == '__main__':
unittest.main()
W powyższym przykładzie test1 i test3 pokazują AssertionError. Komunikat o błędzie wyświetla różnice w obiektach Lista i Słownik.
FAIL: test1 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "asserttest.py", line 5, in test1
self.assertListEqual([2,3,4], [1,2,3,4,5])
AssertionError: Lists differ: [2, 3, 4] != [1, 2, 3, 4, 5]
First differing element 0:
2
1
Second list contains 2 additional elements.
First extra element 3:
4
- [2, 3, 4]
+ [1, 2, 3, 4, 5]
? +++ +++
FAIL: test3 (__main__.SimpleTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "asserttest.py", line 9, in test3
self.assertDictEqual({1:11,2:22},{3:33,2:22,1:11})
AssertionError: {1: 11, 2: 22} != {1: 11, 2: 22, 3: 33}
- {1: 11, 2: 22}
+ {1: 11, 2: 22, 3: 33}
? +++++++
----------------------------------------------------------------------
Ran 3 tests in 0.001s
FAILED (failures = 2)
Klasa TestLoader ma funkcję Discover (). Framework testowy Pythona używa tego do prostego wykrywania testów. Aby moduły i pakiety zawierające testy były kompatybilne, muszą być możliwe do zaimportowania z katalogu najwyższego poziomu.
Poniżej przedstawiono podstawowe użycie wiersza poleceń przy wykrywaniu testów -
Python –m unittest discover
Interpreter próbuje rekurencyjnie załadować wszystkie moduły zawierające test z katalogu bieżącego i katalogów wewnętrznych. Inne opcje wiersza poleceń to -
Sr.No | Opcje i opis |
---|---|
1 | -v, --verbose Gadatliwe wyjście |
2 | -s, --start-directory katalog Katalog do rozpoczęcia wykrywania (. domyślny) |
3 | -p, --pattern wzorzec Wzorzec pasujący do plików testowych (domyślnie test * .py) |
4 | -t, --top-level-directory katalog Katalog najwyższego poziomu projektu (domyślnie katalog startowy) |
Na przykład, aby znaleźć testy w modułach, których nazwy zaczynają się od „assert” w katalogu „testy”, używany jest następujący wiersz poleceń -
C:\python27>python –m unittest –v –s "c:\test" –p "assert*.py"
Wykrywanie testów ładuje testy, importując je. Gdy wykrywanie testowe znajdzie wszystkie pliki testowe z określonego katalogu startowego, zamienia ścieżki na nazwy pakietów do zaimportowania.
Jeśli podasz katalog startowy jako nazwę pakietu, a nie ścieżkę do katalogu, wtedy program odkryje założenie, że niezależnie od lokalizacji importu jest to lokalizacja, którą zamierzałeś, więc nie otrzymasz ostrzeżenia.
Obsługa pomijania testów została dodana od wersji Python 2.7. Możliwe jest pominięcie pojedynczej metody testowej lub klasy TestCase, zarówno warunkowo jak i bezwarunkowo. Struktura umożliwia oznaczenie określonego testu jako „oczekiwanego niepowodzenia”. Ten test zakończy się niepowodzeniem, ale nie zostanie zaliczony jako niepomyślny w TestResult.
Aby bezwarunkowo pominąć metodę, można użyć następującej metody klasy unittest.skip () -
import unittest
def add(x,y):
return x+y
class SimpleTest(unittest.TestCase):
@unittest.skip("demonstrating skipping")
def testadd1(self):
self.assertEquals(add(4,5),9)
if __name__ == '__main__':
unittest.main()
Ponieważ skip () jest metodą klasową, jest poprzedzona znakiem @ token. Metoda przyjmuje jeden argument: komunikat dziennika opisujący przyczynę pominięcia.
Po wykonaniu powyższego skryptu na konsoli wyświetlany jest następujący wynik -
C:\Python27>python skiptest.py
s
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK (skipped = 1)
Znak „s” oznacza, że test został pominięty.
Alternatywna składnia pomijania testu polega na użyciu metody instancji skipTest () wewnątrz funkcji testowej.
def testadd2(self):
self.skipTest("another method for skipping")
self.assertTrue(add(4 + 5) == 10)
Następujące dekoratory implementują pomijanie testów i oczekiwane awarie -
Sr.No | Metoda i opis |
---|---|
1 | unittest.skip(reason) Bezwarunkowo pomiń test z dekoracją. Powód powinien opisywać, dlaczego test jest pomijany. |
2 | unittest.skipIf(condition, reason) Pomiń dekorowany test, jeśli warunek jest prawdziwy. |
3 | unittest.skipUnless(condition, reason) Pomiń udekorowany test, chyba że warunek jest prawdziwy. |
4 | unittest.expectedFailure() Oznacz test jako oczekiwaną awarię. Jeśli test zakończy się niepowodzeniem po uruchomieniu, nie jest liczony jako błąd. |
Poniższy przykład ilustruje użycie warunkowego pomijania i oczekiwanego niepowodzenia.
import unittest
class suiteTest(unittest.TestCase):
a = 50
b = 40
def testadd(self):
"""Add"""
result = self.a+self.b
self.assertEqual(result,100)
@unittest.skipIf(a>b, "Skip over this routine")
def testsub(self):
"""sub"""
result = self.a-self.b
self.assertTrue(result == -10)
@unittest.skipUnless(b == 0, "Skip over this routine")
def testdiv(self):
"""div"""
result = self.a/self.b
self.assertTrue(result == 1)
@unittest.expectedFailure
def testmul(self):
"""mul"""
result = self.a*self.b
self.assertEqual(result == 0)
if __name__ == '__main__':
unittest.main()
W powyższym przykładzie testyub () i testdiv () zostaną pominięte. W pierwszym przypadku a> b jest prawdą, podczas gdy w drugim przypadku b == 0 nie jest prawdą. Z drugiej strony testmul () została oznaczona jako oczekiwana awaria.
Po uruchomieniu powyższego skryptu dwa pominięte testy pokazują „s”, a oczekiwany błąd jest wyświetlany jako „x”.
C:\Python27>python skiptest.py
Fsxs
================================================================
FAIL: testadd (__main__.suiteTest)
Add
----------------------------------------------------------------------
Traceback (most recent call last):
File "skiptest.py", line 9, in testadd
self.assertEqual(result,100)
AssertionError: 90 != 100
----------------------------------------------------------------------
Ran 4 tests in 0.000s
FAILED (failures = 1, skipped = 2, expected failures = 1)
Struktura testowa Pythona zapewnia następujące metody potwierdzania, które sprawdzają, czy wyjątki są zgłaszane.
assertRaises (wyjątek, możliwość wywołania, * args, ** kwds)
Sprawdź, czy wyjątek (pierwszy argument) jest zgłaszany, gdy wywoływana jest funkcja z dowolnym argumentem pozycyjnym lub słowem kluczowym. Test przechodzi, jeśli zostanie zgłoszony oczekiwany wyjątek, jest błędem, jeśli zostanie zgłoszony inny wyjątek, lub nie powiedzie się, jeśli nie zostanie zgłoszony żaden wyjątek. Aby przechwycić dowolną grupę wyjątków, jako wyjątek można przekazać krotkę zawierającą klasy wyjątków.
W poniższym przykładzie zdefiniowano funkcję testową, która sprawdza, czy nie został zgłoszony błąd ZeroDivisionError.
import unittest
def div(a,b):
return a/b
class raiseTest(unittest.TestCase):
def testraise(self):
self.assertRaises(ZeroDivisionError, div, 1,0)
if __name__ == '__main__':
unittest.main()
Funkcja testraise () używa funkcji assertRaises (), aby sprawdzić, czy po wywołaniu funkcji div () następuje dzielenie przez zero. Powyższy kod zgłosi wyjątek. Ale zmienia argumenty na funkcję div () w następujący sposób -
self.assertRaises(ZeroDivisionError, div, 1,1)
Gdy kod jest uruchamiany z tymi zmianami, test kończy się niepowodzeniem, ponieważ nie występuje błąd ZeroDivisionError.
F
================================================================
FAIL: testraise (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "raisetest.py", line 7, in testraise
self.assertRaises(ZeroDivisionError, div, 1,1)
AssertionError: ZeroDivisionError not raised
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures = 1)
assertRaisesRegexp (wyjątek, regexp, callable, * args, ** kwds)
Testuje dopasowanie wyrażenia regularnego do ciągu reprezentującego podniesiony wyjątek. regexp może być obiektem wyrażenia regularnego lub łańcuchem zawierającym wyrażenie regularne odpowiednie do użycia przez funkcję re.search ().
Poniższy przykład pokazuje, jak jest używana funkcja assertRaisesRegexp () -
import unittest
import re
class raiseTest(unittest.TestCase):
def testraiseRegex(self):
self.assertRaisesRegexp(TypeError, "invalid", reg,"Point","TutorialsPoint")
if __name__ == '__main__':
unittest.main()
Tutaj testraseRegex () test nie zawodzi jako pierwszy argument. „Punkt” znajduje się w drugim argumencie.
================================================================
FAIL: testraiseRegex (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:/Python27/raiseTest.py", line 11, in testraiseRegex
self.assertRaisesRegexp(TypeError, "invalid", reg,"Point","TutorialsPoint")
AssertionError: TypeError not raised
----------------------------------------------------------------------
Jednak zmiana jest taka, jak pokazano poniżej -
self.assertRaisesRegexp(TypeError, "invalid", reg,123,"TutorialsPoint")
Zostanie zgłoszony wyjątek TypeError. W związku z tym zostanie wyświetlony następujący wynik -
================================================================
FAIL: testraiseRegex (__main__.raiseTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "raisetest.py", line 11, in testraiseRegex
self.assertRaisesRegexp(TypeError, "invalid", reg,123,"TutorialsPoint")
AssertionError: "invalid" does not match
"first argument must be string or compiled pattern"
----------------------------------------------------------------------
Junit, framework do testów jednostkowych Java (Pyunit jest implementacją JUnit) ma przydatną opcję limitu czasu. Jeśli test zajmie więcej niż określony czas, zostanie oznaczony jako nieudany.
Struktura testowa Pythona nie obsługuje limitu czasu. Jednak trzecia część modułu, zwana dekoratorem limitu czasu, może wykonać zadanie.
Pobierz i zainstaluj moduł z -
https://pypi.python.org/packages/source/t/timeout-decorator/timeout-decorator-0.3.2.tar.gz
- Zaimportuj timeout_decorator w kodzie
- Umieść dekorator limitu czasu przed testem
- @timeout_decorator.timeout(10)
Jeśli metoda testowa poniżej tego wiersza zajmie więcej niż wspomniany limit czasu (10 minut), zostanie zgłoszony błąd TimeOutError. Na przykład -
import time
import timeout_decorator
class timeoutTest(unittest.TestCase):
@timeout_decorator.timeout(5)
def testtimeout(self):
print "Start"
for i in range(1,10):
time.sleep(1)
print "%d seconds have passed" % i
if __name__ == '__main__':
unittest.main()
unittest2 to zestawienie dodatkowych funkcji dodanych do środowiska testowego Pythona w Pythonie 2.7 i nowszych. Został przetestowany pod kątem działania na Pythonie 2.6, 2.7 i 3. *. Najnowszą wersję można pobrać z witrynyhttps://pypi.python.org/pypi/unittest2
Aby użyć unittest2 zamiast unittest, po prostu zamień import unittest na import unittest2.
Klasy w unittest2 wywodzą się z odpowiednich klas w unittest, więc powinno być możliwe użycie infrastruktury działającej w unittest2 bez konieczności natychmiastowego przełączania wszystkich testów na używanie unittest2. Jeśli zamierzasz zaimplementować nowe funkcje, podklasuj swój przypadek testowy zunittest2.TestCase zamiast unittest.TestCase
Poniżej przedstawiono nowe funkcje unittest2 -
addCleanups dla lepszego zarządzania zasobami
Zawiera wiele nowych metod asercji
assertRaises jako menedżer kontekstu, z późniejszym dostępem do wyjątku
Posiada urządzenia na poziomie modułu, takie jak setUpModule i tearDownModule
Zawiera load_tests protokół do ładowania testów z modułów lub pakietów
startTestRun i stopTestRun metody na TestResult
W Pythonie 2.7 wywołujesz unittest funkcje wiersza poleceń (w tym testowe wykrywanie) za pomocą python -m unittest <args>.
Zamiast tego unittest2 zawiera skrypt unit2.
unit2 discover
unit2 -v test_module
Bardziej wydajną obsługę polecenia control-C podczas uruchamiania testowego zapewnia opcja wiersza poleceń -c / - catch do unittest, wraz z catchbreakparametr. Z włączonym zachowaniem typu catch break, control-C pozwoli na zakończenie aktualnie wykonywanego testu, a przebieg testowy zakończy się i zgłosi wszystkie dotychczasowe wyniki. Drugie Ctrl-c podniesie KeyboardInterrupt w zwykły sposób.
Jeśli wywoływana jest procedura obsługi unittest, ale procedura obsługi signal.SIGINT nie jest zainstalowana, wówczas wywołuje domyślną procedurę obsługi. Zwykle będzie to oczekiwane zachowanie przez kod, który zastępuje zainstalowaną procedurę obsługi i jej delegatów. W przypadku testów indywidualnych, które wymagają wyłączenia obsługi unittest control-c, można użyć dekoratora removeHandler ().
Następujące funkcje narzędziowe umożliwiają obsługę funkcji control-c w ramach testów -
unittest.installHandler ()
Zainstaluj program obsługi control-c. Kiedysignal.SIGINT jest odbierany, wszystkie zarejestrowane wyniki są wywoływane TestResult.stop ().
unittest.registerResult (wynik)
Zarejestruj się TestResultobiekt do obsługi control-c. Zarejestrowanie wyniku przechowuje słabe odwołanie do niego, więc nie zapobiega zbieraniu wyniku.
unittest.removeResult (wynik)
Usuń zarejestrowany wynik. Po usunięciu wyniku TestResult.stop () nie będzie już wywoływany na tym obiekcie wynikowym w odpowiedzi na control-c.
unittest.removeHandler (funkcja = Brak)
Wywołana bez argumentów, ta funkcja usuwa program obsługi control-c, jeśli został zainstalowany. Ta funkcja może być również używana jako dekorator testów, aby tymczasowo usunąć procedurę obsługi podczas wykonywania testu.
GUI Test Runner
Moduł unittest jest instalowany w celu interaktywnego wykrywania i uruchamiania testów. To narzędzie, skrypt Pythona „inittestgui.py”, używa modułu Tkinter, który jest portem Pythona dla zestawu narzędzi graficznych TK. Zapewnia łatwy w użyciu graficzny interfejs użytkownika do wykrywania i przeprowadzania testów.
Python unittestgui.py
Kliknij przycisk „Odkryj testy”. Pojawi się małe okno dialogowe, w którym można wybrać katalog i moduły, z których ma zostać uruchomiony test.
Na koniec kliknij przycisk Start. Testy zostaną wykryte z wybranej ścieżki i nazw modułów, a wyniki zostaną wyświetlone w panelu wyników.
Aby zobaczyć szczegóły pojedynczego testu, wybierz i kliknij test w polu wyników -
Jeśli nie znajdziesz tego narzędzia w instalacji Pythona, możesz je pobrać ze strony projektu http://pyunit.sourceforge.net/.
Dostępne jest również narzędzie oparte na zestawie narzędzi wxpython.
Standardowa dystrybucja Pythona zawiera moduł Doctest. Funkcjonalność tego modułu umożliwia wyszukiwanie fragmentów tekstu, które wyglądają jak interaktywne sesje Pythona i wykonuje te sesje, aby sprawdzić, czy działają dokładnie tak, jak pokazano.
Doctest może być bardzo przydatny w następujących scenariuszach -
Aby sprawdzić, czy dokumentacja modułu jest aktualna, weryfikując, czy wszystkie interaktywne przykłady nadal działają zgodnie z dokumentacją.
Aby przeprowadzić testy regresji, sprawdzając, czy interaktywne przykłady z pliku testowego lub obiektu testowego działają zgodnie z oczekiwaniami.
Aby napisać samouczek dla pakietu, obficie zilustrowany przykładami wejścia-wyjścia
W Pythonie „docstring” to ciąg znaków, który pojawia się jako pierwsze wyrażenie w klasie, funkcji lub module. Jest ignorowany, gdy pakiet jest wykonywany, ale jest rozpoznawany przez kompilator i umieszczany w pliku__doc__atrybut otaczającej klasy, funkcji lub modułu. Ponieważ jest dostępny poprzez introspekcję, jest kanonicznym miejscem dokumentacji obiektu.
Zwykłą praktyką jest umieszczanie przykładu użycia różnych części kodu Pythona wewnątrz docstringu. Moduł doctest pozwala zweryfikować, czy te ciągi dokumentacyjne są aktualne i zawierają sporadyczne poprawki w kodzie.
W poniższym kodzie zdefiniowano funkcję silni przeplataną przykładowym użyciem. Aby sprawdzić, czy przykładowe użycie jest poprawne, wywołaj funkcję testmod () w module doctest.
"""
This is the "example" module.
The example module supplies one function, factorial(). For example,
>>> factorial(5)
120
"""
def factorial(x):
"""Return the factorial of n, an exact integer >= 0.
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: x must be >= 0
"""
if not x >= 0:
raise ValueError("x must be >= 0")
f = 1
for i in range(1,x+1):
f = f*i
return f
if __name__ == "__main__":
import doctest
doctest.testmod()
Wprowadź i zapisz powyższy skrypt jako FactDocTest.py i spróbuj wykonać ten skrypt z wiersza poleceń.
Python FactDocTest.py
Żadne dane wyjściowe nie zostaną wyświetlone, chyba że przykład zawiedzie. Teraz zmień wiersz poleceń na następujący -
Python FactDocTest.py –v
Konsola pokaże teraz następujące dane wyjściowe -
C:\Python27>python FactDocTest.py -v
Trying:
factorial(5)
Expecting:
120
ok
Trying:
factorial(-1)
Expecting:
Traceback (most recent call last):
...
ValueError: x must be >= 0
ok
2 items passed all tests:
1 tests in __main__
1 tests in __main__.factorial
2 tests in 2 items.
2 passed and 0 failed.
Test passed.
Z drugiej strony, jeśli kod funkcji silnia () nie daje oczekiwanego wyniku w docstring, zostanie wyświetlony wynik niepowodzenia. Na przykład zmień f = 2 zamiast f = 1 w powyższym skrypcie i ponownie uruchom doctest. Wynik będzie następujący -
Trying:
factorial(5)
Expecting:
120
**********************************************************************
File "docfacttest.py", line 6, in __main__
Failed example:
factorial(5)
Expected:
120
Got:
240
Trying:
factorial(-1)
Expecting:
Traceback (most recent call last):
...
ValueError: x must be >= 0
ok
1 items passed all tests:
1 tests in __main__.factorial
**********************************************************************
1 items had failures:
1 of 1 in __main__
2 tests in 2 items.
1 passed and 1 failed.
***Test Failed*** 1 failures.
Doctest: Sprawdzanie przykładów w pliku tekstowym
Innym prostym zastosowaniem doctest jest testowanie interaktywnych przykładów w pliku tekstowym. Można to zrobić za pomocą funkcji testfile ().
Poniższy tekst jest przechowywany w pliku tekstowym o nazwie „przykład.txt”.
Using ''factorial''
-------------------
This is an example text file in reStructuredText format. First import
''factorial'' from the ''example'' module:
>>> from example import factorial
Now use it:
>>> factorial(5)
120
Zawartość pliku jest traktowana jako ciąg dokumentów. Aby zweryfikować przykłady w pliku tekstowym, użyj funkcji testfile () modułu doctest.
def factorial(x):
if not x >= 0:
raise ValueError("x must be >= 0")
f = 1
for i in range(1,x+1):
f = f*i
return f
if __name__ == "__main__":
import doctest
doctest.testfile("example.txt")
Podobnie jak w przypadku testmod (), testfile () nie wyświetli niczego, chyba że przykład zawiedzie. Jeśli przykład się nie powiedzie, to przykład (y) niepowodzenia i przyczyna (y) błędów są drukowane do konsoli, przy użyciu tego samego formatu co testmod ().
W większości przypadków kopiowanie i wklejanie sesji interaktywnej konsoli działa dobrze, ale doctest nie próbuje wykonać dokładnej emulacji żadnej konkretnej powłoki Pythona.
Wszelkie oczekiwane dane wyjściowe muszą natychmiast następować po ostatniej linii „>>>” lub „...” zawierającej kod, a oczekiwane dane wyjściowe (jeśli istnieją) rozciągają się do następnej linii „>>>” lub całkowicie białej.
Oczekiwane wyjście nie może zawierać całkowicie białej linii, ponieważ taka linia jest używana do sygnalizowania końca oczekiwanego wyjścia. Jeśli oczekiwane wyjście zawiera pustą linię, wstaw <BLANKLINE> w swoim przykładzie doctest w każdym miejscu, w którym oczekiwana jest pusta linia.
Doctest API obraca się wokół następujących dwóch klas kontenerów używanych do przechowywania interaktywnych przykładów z docstrings -
Example - Pojedyncza instrukcja języka Python w połączeniu z oczekiwanym wynikiem.
DocTest - Zbiór przykładów, zwykle wyodrębnionych z pojedynczego ciągu dokumentów lub pliku tekstowego.
Następujące dodatkowe klasy przetwarzania są zdefiniowane w celu wyszukiwania, analizowania, uruchamiania i sprawdzania przykładów doctest -
DocTestFinder - Znajduje wszystkie ciągi dokumentów w danym module i używa DocTestParser do tworzenia DocTest z każdego ciągu dokumentów, który zawiera interaktywne przykłady.
DocTestParser - Tworzy obiekt doctest z łańcucha (np. Dokumentacja obiektu).
DocTestRunner - Wykonuje przykłady w doctest i używa OutputChecker do zweryfikowania ich danych wyjściowych.
OutputChecker - porównuje rzeczywiste dane wyjściowe z przykładu doctest z oczekiwanymi wynikami i decyduje, czy są one zgodne.
Klasa DocTestFinder
Jest to klasa przetwarzania używana do wyodrębniania doctestów, które są istotne dla danego obiektu, z jego dokumentacji i dokumentów zawartych w nim. Obecnie testy doctesty można wyodrębnić z następujących typów obiektów - modułów, funkcji, klas, metod, metod statycznych, metod klas i właściwości.
Ta klasa definiuje metodę find (). Zwraca listę DocTestów, które są zdefiniowane przez dokumentację obiektu lub przez dowolny z zawartych w nim dokumentów.
DocTestParser Class
Jest to klasa przetwarzająca używana do wyodrębniania interaktywnych przykładów z łańcucha i używania ich do tworzenia obiektu DocTest. Ta klasa definiuje następujące metody -
get_doctest() - Wyodrębnij wszystkie przykłady doctest z podanego ciągu i zbierz je do pliku DocTest obiekt.
get_examples(string[, name]) - Wyodrębnij wszystkie przykłady doctest z podanego ciągu i zwróć je jako listę Exampleobiekty. Numery linii rozpoczynają się od 0. Opcjonalna nazwa argumentu to nazwa identyfikująca ten ciąg i jest używana tylko w przypadku komunikatów o błędach.
parse(string[, name]) - Podzielić podany ciąg na przykłady i tekst interweniujący i zwrócić je jako listę naprzemienną Examplesi struny. Numery wierszy dlaExamplessą oparte na 0. Opcjonalna nazwa argumentu to nazwa identyfikująca ten ciąg i jest używana tylko w przypadku komunikatów o błędach.
Klasa DocTestRunner
Jest to klasa przetwarzania używana do wykonywania i weryfikowania interaktywnych przykładów w DocTest. Zdefiniowano w nim następujące metody -
report_start ()
Zgłoś, że program uruchamiający testy ma zamiar przetworzyć podany przykład. Ta metoda jest udostępniana, aby umożliwić podklasyDocTestRunnerdostosować ich wyjście; nie powinno być wywoływane bezpośrednio
report_success ()
Zgłoś, że podany przykład został pomyślnie uruchomiony. Ta metoda umożliwia podklasom DocTestRunner dostosowywanie swoich danych wyjściowych; nie powinno być wywoływane bezpośrednio.
report_failure ()
Zgłoś, że podany przykład nie powiódł się. Ta metoda jest udostępniana, aby umożliwić podklasyDocTestRunnerdostosować ich wyjście; nie powinno być wywoływane bezpośrednio.
report_uxpressected_exception ()
Zgłoś, że podany przykład wywołał nieoczekiwany wyjątek. Ta metoda umożliwia podklasom DocTestRunner dostosowywanie swoich danych wyjściowych; nie powinno być wywoływane bezpośrednio.
uruchom (test)
Uruchom przykłady w test (obiekt DocTest) i wyświetl wyniki przy użyciu funkcji zapisu out .
summarize ([verbose])
Wydrukuj podsumowanie wszystkich przypadków testowych, które zostały uruchomione przez ten DocTestRunner, i zwróć nazwaną krotkę TestResults (niepowodzenie, próba). Opcjonalny gadatliwy kontroli argumentów jak szczegółowe podsumowanie jest. Jeśli szczegółowość nie jest określona, używana jest szczegółowość DocTestRunner.
Klasa OutputChecker
Ta klasa służy do sprawdzania, czy rzeczywiste dane wyjściowe z przykładu doctest są zgodne z oczekiwanymi danymi wyjściowymi.
W tej klasie zdefiniowano następujące metody -
check_output ()
Powrót Truejeśli rzeczywisty wynik z przykładu ( got ) pasuje do oczekiwanego wyniku ( chcesz ). Te ciągi są zawsze uważane za zgodne, jeśli są identyczne; ale w zależności od tego, jakich flag opcji używa program uruchamiający testy, możliwych jest również kilka niedokładnych typów dopasowania. Więcej informacji na temat flag opcji można znaleźć w sekcji Flagi i dyrektywy opcji.
output_difference ()
Zwraca ciąg znaków opisujący różnice między oczekiwanymi danymi wyjściowymi dla danego przykładu ( przykład ) a rzeczywistymi wynikami ( otrzymano ).
Integracja DocTest z Unittest
Moduł doctest udostępnia dwie funkcje, które można wykorzystać do tworzenia zestawów testów unittest z modułów i plików tekstowych zawierających testy doctest. Aby zintegrować się z unittest test discovery, dołącz funkcję load_tests () w swoim module testowym -
import unittest
import doctest
import doctestexample
def load_tests(loader, tests, ignore):
tests.addTests(doctest.DocTestSuite(doctestexample))
return tests
Zostanie utworzony połączony TestSuite z testów z unittest i doctest, który można teraz wykonać za pomocą metody main () modułu unittest lub metody run ().
Poniżej przedstawiono dwie główne funkcje tworzenia unittest.TestSuite instancje z plików tekstowych i modułów z doctests -
doctest.DocFileSuite ()
Służy do konwersji testów doctest z jednego lub większej liczby plików tekstowych do pliku unittest.TestSuite. Zwrócony unittest.TestSuite ma być uruchamiany przez unittest framework i uruchamia interaktywne przykłady w każdym pliku. Jeśli którykolwiek z przykładów w pliku nie powiedzie się, zsyntetyzowany test jednostkowy kończy się niepowodzeniem, a plikfailureException zgłaszany jest wyjątek pokazujący nazwę pliku zawierającego test i (czasami przybliżony) numer wiersza.
doctest.DocTestSuite ()
Służy do konwersji testów doctest dla modułu na plik unittest.TestSuite.
Zwrócony unittest.TestSuite ma być uruchamiany przez unittest framework i uruchamia każdy doctest w module. Jeśli którykolwiek z testów doc nie powiedzie się, zsyntetyzowany test jednostkowy kończy się niepowodzeniem, a plikfailureException zgłaszany jest wyjątek pokazujący nazwę pliku zawierającego test i (czasami przybliżony) numer wiersza
Pod osłonami DocTestSuite () tworzy plik unittest.TestSuite poza instancjami doctest.DocTestCase, a DocTestCase jest podklasą unittest.TestCase.
Podobnie DocFileSuite () tworzy unittest.TestSuite z instancji doctest.DocFileCase, a DocFileCase jest podklasą DocTestCase.
Tak więc oba sposoby tworzenia unittest.TestSuite uruchamiają instancje DocTestCase. Gdy samodzielnie uruchamiasz funkcje doctest, możesz bezpośrednio kontrolować używane opcje doctest, przekazując flagi opcji do funkcji doctest.
Jeśli jednak piszesz unittest framework, unittest ostatecznie kontroluje, kiedy i jak testy są uruchamiane. Autor frameworka zazwyczaj chce kontrolować opcje raportowania doctest (być może np. Określone opcjami wiersza poleceń), ale nie ma sposobu, aby przekazać opcje przez unittest do doctest uruchomieniowych testów.
W 2004 roku Holger Krekel zmienił nazwę swojego stdpakiet, którego nazwa była często mylona z nazwą biblioteki standardowej dostarczanej z Pythonem, do (tylko nieco mniej mylącej) nazwy „py”. Chociaż pakiet zawiera kilka pakietów podrzędnych, jest obecnie prawie całkowicie znany ze swojego frameworka py.test.
Framework py.test ustanowił nowy standard testowania w Pythonie i stał się obecnie bardzo popularny wśród wielu programistów. Eleganckie i Pythonowe idiomy, które wprowadził do pisania testów, umożliwiły pisanie zestawów testów w znacznie bardziej zwartym stylu.
py.test to niekodowana alternatywa dla standardowego modułu unittest w Pythonie. Pomimo tego, że jest w pełni funkcjonalnym i rozszerzalnym narzędziem testowym, oferuje prostą składnię. Tworzenie zestawu testów jest tak proste, jak napisanie modułu z kilkoma funkcjami.
py.test działa na wszystkich systemach operacyjnych POSIX i WINDOWS (XP / 7/8) z wersjami Pythona 2.6 i nowszymi.
Instalacja
Użyj poniższego kodu, aby załadować moduł pytest w bieżącej dystrybucji języka Python, a także narzędzie py.test.exe. Testy można przeprowadzać przy użyciu obu.
pip install pytest
Stosowanie
Możesz po prostu użyć instrukcji assert do potwierdzenia oczekiwań testowych. introspekcja asercyjna pytest inteligentnie poda wartości pośrednie wyrażenia assert, uwalniając Cię od konieczności poznania wielu nazwJUnit legacy methods.
# content of test_sample.py
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
Użyj następującego wiersza poleceń, aby uruchomić powyższy test. Po uruchomieniu testu na konsoli wyświetlany jest następujący wynik -
C:\Python27>scripts\py.test -v test_sample.py
============================= test session starts =====================
platform win32 -- Python 2.7.9, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- C:\Pyth
on27\python.exe
cachedir: .cache
rootdir: C:\Python27, inifile:
collected 1 items
test_sample.py::test_answer FAILED
================================== FAILURES =====================
_________________________________ test_answer _________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:7: AssertionError
========================== 1 failed in 0.05 seconds ====================
Test można również uruchomić z wiersza poleceń, dołączając moduł pytest za pomocą przełącznika –m.
python -m pytest test_sample.py
Grupowanie wielu testów w klasę
Gdy zaczniesz mieć więcej niż kilka testów, często sensowne jest logiczne grupowanie testów w klasy i moduły. Napiszmy klasę zawierającą dwa testy -
class TestClass:
def test_one(self):
x = "this"
assert 'h' in x
def test_two(self):
x = "hello"
assert hasattr(x, 'check')
Zostanie wyświetlony następujący wynik testu -
C:\Python27>scripts\py.test -v test_class.py
============================= test session starts =====================
platform win32 -- Python 2.7.9, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- C:\Pyt
on27\python.exe
cachedir: .cache
rootdir: C:\Python27, inifile:
collected 2 items
test_class.py::TestClass::test_one PASSED
test_class.py::TestClass::test_two FAILED
================================== FAILURES =====================
_____________________________ TestClass.test_two ______________________________
self = <test_class.TestClass instance at 0x01309DA0>
def test_two(self):
x = "hello"
> assert hasattr(x, 'check')
E assert hasattr('hello', 'check')
test_class.py:7: AssertionError
===================== 1 failed, 1 passed in 0.06 seconds ======================
Projekt nos został wydany w 2005 roku, rok później py.testotrzymał swoją nowoczesną postać. Został napisany przez Jasona Pellerina, aby obsługiwał te same idiomy testowe, które były pionierami w py.test, ale w pakiecie, który jest łatwiejszy w instalacji i utrzymaniu.
Plik nose moduł można zainstalować za pomocą narzędzia pip
pip install nose
Spowoduje to zainstalowanie modułu nose w bieżącej dystrybucji Pythona, a także nosetest.exe, co oznacza, że test można uruchomić przy użyciu tego narzędzia, a także przełącznika –m.
C:\python>nosetests –v test_sample.py
Or
C:\python>python –m nose test_sample.py
nose zbiera testy z unittest.TestCaseoczywiście podklasy. Możemy również napisać proste funkcje testowe, a także klasy testowe, które nie są podklasami unittest.TestCase. Nose zapewnia również szereg pomocnych funkcji do pisania testów czasowych, testowania wyjątków i innych typowych przypadków użycia.
nosezbiera testy automatycznie. Nie ma potrzeby ręcznego zbierania przypadków testowych do zestawów testów. Wykonywanie testów jest responsywne, ponieważnose rozpoczyna wykonywanie testów zaraz po załadowaniu pierwszego modułu testowego.
Podobnie jak w przypadku najgorszego modułu, nose obsługuje urządzenia na poziomie pakietu, modułu, klasy i przypadku testowego, więc kosztowna inicjalizacja może być wykonywana tak rzadko, jak to możliwe.
Podstawowe użycie
Rozważmy nosetest.py podobny do skryptu używanego wcześniej -
# content of nosetest.py
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
Aby uruchomić powyższy test, użyj następującej składni wiersza poleceń -
C:\python>nosetests –v nosetest.py
Dane wyjściowe wyświetlane na konsoli będą wyglądać następująco -
nosetest.test_answer ... FAIL
================================================================
FAIL: nosetest.test_answer
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python34\lib\site-packages\nose\case.py", line 198, in runTest
self.test(*self.arg)
File "C:\Python34\nosetest.py", line 6, in test_answer
assert func(3) == 5
AssertionError
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures = 1)
nose można zintegrować z DocTest za pomocą with-doctest opcja w linii poleceń athe bove.
\nosetests --with-doctest -v nosetest.py
Możesz użyć nose w skrypcie testowym -
import nose
nose.main()
Jeśli nie chcesz, aby skrypt testowy kończył się z 0 w przypadku sukcesu i 1 w przypadku niepowodzenia (np. Unittest.main), użyj zamiast tego nose.run () -
import nose
result = nose.run()
Wynik będzie prawdziwy, jeśli przebieg testowy powiedzie się, lub fałszywy, jeśli się nie powiedzie lub zgłosi nieprzechwycony wyjątek.
noseobsługuje urządzenia (metody konfiguracji i usuwania) na poziomie pakietu, modułu, klasy i testu. Podobnie jak w przypadku urządzeń py.test lub unittest, setup zawsze uruchamia się przed jakimkolwiek testem (lub kolekcją testów dla pakietów i modułów testowych); teardown jest uruchamiane, jeśli instalacja zakończyła się pomyślnie, niezależnie od stanu uruchomienia testowego.
Moduł nose.tools zapewnia szereg pomocy testowych, które mogą okazać się przydatne, w tym dekoratory do ograniczania czasu wykonywania testów i testowania pod kątem wyjątków oraz wszystkie te same metody assertX, które można znaleźć w unittest.TestCase.
nose.tools.ok_(expr, msg = None) - Skrót do potwierdzenia.
nose.tools.eq_(a, b, msg = None) - Skrót dla „assert a == b,„% r! =% R ”% (a, b)
nose.tools.make_decorator(func) - Zawija dekorator testu, aby poprawnie odtworzyć metadane dekorowanej funkcji, w tym dodatkowe elementy nosa (mianowicie ustawienie i rozerwanie).
nose.tools.raises(*exceptions) - Test musi wywołać jeden z oczekiwanych wyjątków, aby przejść.
nose.tools.timed(limit) - Test musi zakończyć się w określonym czasie, aby zdał
nose.tools.istest(func) - Dekorator do oznaczania funkcji lub metody jako testu
nose.tools.nottest(func) - Dekorator, aby oznaczyć funkcję lub metodę jako niebędącą testem
Testowanie parametryczne
Struktura testowa Pythona, unittest, nie ma prostego sposobu uruchamiania sparametryzowanych przypadków testowych. Innymi słowy, nie można łatwo przekazać argumentów do plikuunittest.TestCase z zewnątrz.
Jednak pytest testuje parametryzację portów modułu na kilka dobrze zintegrowanych sposobów -
pytest.fixture() umożliwia zdefiniowanie parametryzacji na poziomie funkcji urządzeń.
@pytest.mark.parametrizeumożliwia zdefiniowanie parametryzacji na poziomie funkcji lub klasy. Zapewnia wiele zestawów argumentów / urządzeń dla określonej funkcji testowej lub klasy.
pytest_generate_tests umożliwia implementację własnego, niestandardowego schematu lub rozszerzeń dynamicznej parametryzacji.
Zewnętrzny moduł „parametryzowany nosem” umożliwia sparametryzowane testowanie w dowolnej strukturze testowej Pythona. Można go pobrać z tego linku -https://github.com/wolever/nose-parameterized