Last modified: November 21, 2022
This article is written in: 🇵🇱
Testy jednostkowe stanowią kluczowy element w procesie wytwarzania oprogramowania, mając na celu weryfikację indywidualnych fragmentów kodu (zazwyczaj funkcji lub metod). Pozwalają programiście mieć pewność, że napisane przez niego komponenty działają zgodnie z oczekiwaniami oraz pomagają w identyfikacji i naprawie błędów na wczesnym etapie.
Czerwone testy:
Zielone testy:
Technika "test driven development" (TDD) to podejście do tworzenia oprogramowania, w którym testy są tworzone przed kodem źródłowym. Proces tworzenia oprogramowania w podejściu TDD jest cykliczny i składa się z trzech głównych etapów:
Korzystanie z TDD pomaga w utrzymaniu czystego kodu, minimalizuje ryzyko błędów i zachęca do myślenia o projektowaniu i architekturze systemu od samego początku procesu tworzenia oprogramowania.
Dla wielu projektów, zwłaszcza tych większych, odpowiednia organizacja plików i katalogów jest kluczem do utrzymania przejrzystości i efektywności. Rozdzielenie kodu produkcyjnego od testów nie tylko pomaga w zarządzaniu plikami, ale także ułatwia konfigurację narzędzi CI/CD oraz automatyzację testów.
Przykładowa struktura folderów dla projektu z testami może wyglądać tak:
projekt/
│
├── przykladowy_pakiet/
│ ├── __init__.py
│ ├── modul_a.py
│ └── modul_b.py
│
└── tests/
├── __init__.py
├── test_modul_a.py
└── test_modul_b.py
Kluczową ideą jest tu utrzymanie logicznej struktury, która odzwierciedla organizację kodu produkcyjnego. Dzięki temu, w miarę rozrostu projektu, łatwo będzie dodawać, modyfikować i lokalizować testy.
W Pythonie istnieją dwie główne biblioteki do pisania i uruchamiania testów jednostkowych:
Cecha | unittest | pytest |
Typ | Standardowa biblioteka w Pythonie do testów jednostkowych | Zewnętrzna biblioteka, która stała się bardzo popularna w społeczności Pythona |
Tworzenie testów | Umożliwia tworzenie testów, zestawów testów oraz uruchamianie ich | Charakteryzuje się prostotą i bardziej naturalnym stylem pisania testów |
Mechanizmy asercji | Posiada wbudowane mechanizmy asercji | Posiada bogatą funkcjonalność w zakresie parametryzacji testów, używania tzw. "fixtures" oraz wtyczek |
Przygotowanie środowiska testów | Posiada setup i teardown dla przygotowywania środowiska testów | - |
Ostateczny wybór pomiędzy unittest
a pytest
zależy od potrzeb projektu i preferencji zespołu. Niezależnie od wyboru, regularne pisanie i uruchamianie testów jednostkowych jest kluczem do tworzenia niezawodnego oprogramowania.
unittest
to standardowa biblioteka w Pythonie przeznaczona do tworzenia testów jednostkowych. Podąża ona za paradygmatem programowania obiektowego, co oznacza, że testy są organizowane w postaci klas, a mechanizmy takie jak dziedziczenie mogą być wykorzystywane do tworzenia hierarchii testów czy rozszerzania funkcjonalności.
Kluczowe cechy unittest
:
unittest.TestCase
.assert
do weryfikacji warunków (np. assertEqual
, assertTrue
).setUp
i tearDown
do przygotowywania i sprzątania po teście.Przykład kodu:
import unittest
def int_to_roman(num):
val = [
1000, 900, 500, 400,
100, 90, 50, 40,
10, 9, 5, 4,
1
]
syms = [
"M", "CM", "D", "CD",
"C", "XC", "L", "XL",
"X", "IX", "V", "IV",
"I"
]
roman_num = ''
i = 0
while num > 0:
for _ in range(num // val[i]):
roman_num += syms[i]
num -= val[i]
i += 1
return roman_num
class TestRomanNumerals(unittest.TestCase):
def test_conversion(self):
self.assertEqual(int_to_roman(1), 'I')
self.assertEqual(int_to_roman(4), 'IV')
self.assertEqual(int_to_roman(40), 'XL')
self.assertEqual(int_to_roman(99), 'XCIX')
self.assertEqual(int_to_roman(1000), 'M')
W powyższym przykładzie:
int_to_roman
konwertuje liczby całkowite na ich reprezentacje w postaci rzymskiej.TestRomanNumerals
dziedziczy po unittest.TestCase
i służy do testowania funkcji int_to_roman
.Aby uruchomić testy jednostkowe, można użyć następującego polecenia w konsoli:
python -m unittest nazwa_pliku_testowego.py
Pamiętaj, by nazwy plików z testami zaczynały się od słowa "test", ponieważ unittest szuka takich plików podczas skanowania katalogów.
pytest
to popularna i wszechstronna biblioteka do tworzenia testów w Pythonie. W porównaniu z unittest
, pytest
oferuje bardziej skondensowany i czytelny sposób definiowania testów, eliminując potrzebę tworzenia klas i korzystania z funkcji assert
. Dodatkowo, pytest
jest znany ze swojego rozbudowanego wyjścia i możliwości diagnozy, które pomagają w identyfikowaniu i rozwiązywaniu problemów w testach.
Kluczowe cechy pytest
:
assertEqual
ani innych metod specyficznych dla unittest
. Wystarczy użyć standardowego Pythonowego assert
.Przykład kodu z użyciem:
def int_to_roman(num):
val = [
1000, 900, 500, 400,
100, 90, 50, 40,
10, 9, 5, 4,
1
]
syms = [
"M", "CM", "D", "CD",
"C", "XC", "L", "XL",
"X", "IX", "V", "IV",
"I"
]
roman_num = ''
i = 0
while num > 0:
for _ in range(num // val[i]):
roman_num += syms[i]
num -= val[i]
i += 1
return roman_num
def test_int_to_roman():
assert int_to_roman(1) == 'I'
assert int_to_roman(4) == 'IV'
assert int_to_roman(40) == 'XL'
assert int_to_roman(99) == 'XCIX'
assert int_to_roman(1000) == 'M'
W powyższym przykładzie:
int_to_roman
konwertuje liczby całkowite na ich reprezentacje w postaci rzymskiej.test_int_to_roman
przeprowadza serię testów, sprawdzając różne przypadki konwersji.Aby uruchomić testy napisane z użyciem pytest, można użyć następującego polecenia w konsoli:
pytest nazwa_pliku_testowego.py
Pamiętaj, by nazwy plików z testami oraz same funkcje testowe zaczynały się od słowa "test", ponieważ pytest szuka takich funkcji/plików podczas skanowania katalogów.
Odkrycie błędu w twoim kodzie to dopiero początek drogi. Oto kroki, które warto podjąć, aby odnaleźć i skutecznie naprawić problem:
foo()
, dodaj lub modyfikuj istniejący test test_foo()
w taki sposób, aby odzwierciedlał sytuację prowadzącą do błędu. Po uruchomieniu tego testu powinieneś otrzymać czerwony komunikat, informujący o niepowodzeniu testu.test_foo()
zakończył się sukcesem.W procesie tworzenia oprogramowania wykorzystuje się różne rodzaje testów, aby upewnić się, że system działa prawidłowo na różnych poziomach. Oto trzy główne typy testów:
Optymalne testowanie oprogramowania wymaga odpowiedniego balansu między tymi typami testów. Zbyt mało testów jednostkowych może prowadzić do konieczności intensywniejszego testowania na wyższych poziomach. Według rekomendacji zawartych w książce "Software Engineering at Google", proporcje podziału testów powinny być następujące:
Podczas tworzenia aplikacji niezmiernie ważne jest, aby mieć dostęp do rzetelnych danych testowych. Może to być kluczowe, szczególnie gdy aplikacja wymaga interakcji z bazami danych lub innymi zewnętrznymi źródłami danych. Skrypty generujące dane testowe pozwalają szybko i efektywnie wypełniać system wartościami, które są zbliżone do rzeczywistych. Dzięki temu programiści i testerzy mogą ocenić, jak aplikacja zachowa się w prawdziwym środowisku, bez ryzyka wprowadzenia błędów w produkcji.
Automatyzacja testów jest kluczowym elementem współczesnego procesu rozwoju oprogramowania, umożliwiając szybsze wykrywanie błędów i pewność, że wprowadzone zmiany nie wpłynęły negatywnie na istniejącą funkcjonalność. Współczesne narzędzia do automatyzacji testów i integracji ciągłej (CI/CD) umożliwiają nie tylko automatyczne uruchamianie testów, ale także automatyczne wdrażanie aplikacji w odpowiednich środowiskach.
Oto kilka powszechnie używanych narzędzi i platform:
Cecha | Travis CI | Jenkins | GitLab CI/CD | CircleCI | Selenium |
Typ | Chmurowa usługa CI | Narzędzie CI/CD open source | Zintegrowany system CI/CD | Chmurowa platforma CI/CD | Narzędzie do testowania aplikacji webowych |
Integracja z GitHubem | Idealna dla projektów hostowanych na GitHubie | Możliwa | Zintegrowany z GitLabem | Możliwa | Nie dotyczy |
Konfiguracja | Prosta konfiguracja | Elastyczna konfiguracja, bogaty ekosystem wtyczek | Definiowanie potoków pracy przy użyciu plików konfiguracyjnych | Automatyczne budowanie, testowanie i wdrażanie aplikacji | Symulacja interakcji użytkownika, używanie z wieloma językami programowania |
Środowisko | Chmura | Lokalny serwer lub chmura | GitLab | Chmura | Różne przeglądarki |
Popularność | Wysoka popularność wśród projektów open source na GitHubie | Bardzo popularne w dużych organizacjach i projektach korporacyjnych | Wysoka popularność wśród użytkowników GitLaba | Mniej popularne | Bardzo popularne w testowaniu aplikacji webowych |