Pytest – DDT w praktyce #1

Data Driven Testing w praktyce, przy użyciu Python oraz pyTesta. W pierwszej części ogólne informacje dotyczące koncepcji oraz przykład przygotowania testów dla prostej aplikacji systemu wbudowanego.

Pytest DDT w praktyce

Pytest DDT w praktyce


Co to jest DDT?

Co w ogóle znaczy DDT? Zgodnie z definicją Słownika Terminów Testowych ISTQB:

(Data Driven Testing) testowanie sterowane danymi – Technika automatyzacji testów, która polega na umieszczeniu danych testowych i oczekiwanych wyników w tabeli lub arkuszu kalkulacyjnym, tak aby jeden skrypt mógł wykonać wszystkie testy z tabeli. Testowanie sterowane danymi jest często używane jako uzupełnienie narzędzi wykonywania testów, takich jak narzędzia rejestrująco-odtwarzające.

Osobiście ograniczyłbym to do stwierdzenia, że jest to technika umożliwiająca sterowanie testami przy użyciu danych.

Dlaczego akurat DDT?

W ostatnim czasie stanąłem naprzeciwko problemu dostosowania moich testów do różnych wersji danego modułu. Po analizie kilku podejść do zadania oraz uwzględnieniu faktu, iż każdy test musiałby zostać przepisany tyle razy, ile jest wersji modułu, zdecydowałem się na wykorzystanie tutaj technologii DDT.

W znacznym stopniu ułatwiło to późniejsze utrzymanie testów, przy jednoczesnym zachowaniu pełnej kontroli nad każdą wersją modułów.

Gdzie trzymać dane?

Najlepszą odpowiedzią na to pytanie jest: tam, gdzie jest nam wygodnie. Dane nie muszą się znajdować w Excelu czy tabeli. Mogą one być przechowywane w dowolny sposób, w dowolnym narzędziu czy w dowolnej formie. Nasz wybór powinno w głównej mierze determinować to, do jakich narzędzi mamy dostęp, jakie narzędzia znamy, a także które narzędzia ułatwią nam późniejsze utrzymanie. Na przykład w przypadku automatyzacji — dane można przechowywać w pliku parametryzacyjnym w postaci list lub w pliku JSON.

Koncepcja

Ogólna koncepcja testowania DDT polega na separacji testów od danych. Nawiązując tutaj do automatyzacji, oznacza to, że skrypty przyjmują dane z zewnątrz. Jednocześnie dane te są wymagane do działania skryptu. DDT nie definiuje w żaden sposób podawanych danych, a co za tym idzie poziomu, czy głębokości, do której wykorzystujemy określone parametry. Dlatego też prosty skrypt może przyjmować tylko określone wartości zadane i oczekiwane, natomiast zaawansowany skrypt może wykorzystywać również kroki czy inne działania, które są specyficzne dla danego testu.

DDT + Python + pyTest w praktyce

W celu lepszego przedstawienia tematu posłużę się prostym przykładem, testowania kalkulatora. Założeniem jest, że jego interfejs daje nam możliwość automatycznego klikania po przyciskach. W przykładach zostanie wykorzystany Python w połączeniu z frameworkiem PyTest. Jak zacząć używać PyTest, możesz znaleźć tutaj.

Przykładowy test mógłby wyglądać tak:

def test_add_5_3():
    povide_number(5
    press_button('+')
    provide_number(3)
    press_button('=')
    assert get_result() is 8

Patrząc na ten test, widzimy, że w przypadku próby wersyfikacji kolejnych działań, liczba testów proporcjonalnie rośnie. W tym momencie przychodzi nam z pomocą właśnie DDT. Wykorzystując przy tym możliwość parametryzacji testów w pyTest, możemy powyższy test zmienić na:

input_data = (
    (5, 3, 8),
    )
 
@pytest.mark.parametrize("num1, num2, result", input_data)
def test_addition(num1, num2, result):
    provide_number(num1)
    press_button('+')
    provide_number(num2)
    press_button('=')
    assert get_result() is result

W powyższym przykładzie widzimy, że wprowadzamy jako parametry do funkcji dane wejściowe, jak i oczekiwany wynik. Dzięki temu w bardzo prosty sposób możemy dodawać kolejne testy:

input_data = (
    (5, 3, 8),
    (1, 2, 3),
    (7, 8, 15),
    (4, 2, 6),
    )

W kolejnym kroku możemy dodać możliwość parametryzacji rodzajów operacji matematycznych:

input_data = (
    (5, '+', 3, 8),
    (1, '*', 2, 2),
    (7, '-', 8, -1),
    (4, '/', 2, 2),
    )
 
@pytest.mark.parametrize("num1, operation, num2, result", input_data)
def test_operation(num1, operation,  num2, result):
    provide_number(num1)
    press_button(operation)
    provide_number(num2)
    press_button('=')
    assert get_result() is result

Jak widzimy w powyższym przypadku stworzenie i utrzymanie nawet dużej liczby testów w tym przypadku jest stosunkowo proste.

close

Newsletter