Pytest – DDT w praktyce #2

Data Driven Testing w praktyce, przy użyciu Python oraz pyTesta. W części drugiej przyjrzymy się bliżej testowaniu wariantów jednej aplikacji systemu wbudowanego.

Pytest DDT w praktyce

Pytest DDT w praktyce


W poprzednim artykule związanym z Data Driven Testing, zaprezentowałem podstawowe użycie DDT, posługując się prostym przykładem. Obecnie postaram się opisać temat w przypadku testowania bardziej złożonego systemu. W tym celu założę, że również potrzebujemy przetestować kalkulator, jednak będziemy posiadać jego kilka wariantów:

Wariant A:

  • obsługuje działania: +, -, *
  • operuje na liczbach: <0..10>
  • wbudowana funkcja: x^2

Wariant B:

  • obsługuje działania: +, -, *
  • operuje na liczbach: <0..255>

Wariant C:

  • obsługuje działania: +, -, *, /
  • operuje na liczbach: <0..255>
  • zaokrągla: 2 miejsca dziesiętne
  • wbudowana funkcja: x^2

W celu przetestowania wszystkich dostępnych wersji kalkulatora można napisać dla każdej wersji testy jak w poprzednim artykule (z odpowiednimi parametrami) lub ograniczyć do stworzenia zestawów danych, w taki sposób, aby można było uruchomić testy z konkretnym zestawem parametrów, odpowiednich dla testowanego wariantu.

Zaczynamy…

Przypomnijmy sobie test z poprzedniego artykułu:

@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

Wykorzystując ten test, możemy pokryć warunki dotyczące obsługi działań oraz odpowiednie zakresy liczb. Poniżej dopiszmy test pozwalający pokryć specjalne operacje, czyli w naszym przypadku podnoszenie liczby do potęgi drugiej. Następnie oba testy umieśćmy w pliku: test_calculator.py. Obecnie plik powinien wyglądać tak:

import pytest
from input_c import input_operation, input_power_function
 
@pytest.mark.parametrize('numA, operation, numB, result', input_operation)
def test_operation(numA, operation, numB, result):
    provide_number(num1)
    press_button(operation)
    provide_number(num2)
    press_button('=')
    assert get_result() is result
 
 
@pytest.mark.parametrize('number, result', input_power_function)
def test_power_function(number, result):
    provide_number(number)
    press_x2()
    assert get_result() is result

Parametryzacja

W kolejnym kroku wybierzemy odpowiednie parametry do naszych testów. Musimy jednak przy tym pamiętać, że nawet jeśli jakiś test nie jest wykorzystywany dla konkretnego wariantu, trzeba dla niego stworzyć pustą listę parametrów. W przeciwnym wypadku, przy próbie uruchomienia testów bez parametrów, zobaczymy wyjątek związany z ich brakiem. Parametry dla każdego wariantu zapiszemy w osobowych plikach. Powinny one wyglądać w następujący sposób:

1. Wariant A – input_a.py

input_operation = (
    (1, '*', 10, 10),
    (10, '+', 0, 10),
    (5, '-', 10, -5),
)
 
input_power_function = (
    (1, 1), 
    (255, 65025),
)

2. Wariant B – input_b.py

input_operation = (
    (1, '*', 255, 255),
    (255, '+', 0, 255),
    (100, '-', 255, -155),
)
 
input_power_function = (
    )

3. Wariant C – input_c.py

input_operation = (
    (1, '*', 255, 255),
    (255, '+', 0, 255),
    (100, '-', 255, -155),
    (170, '-', 32, 5.31),
)
 
input_power_function = (
    (0, 0),
    (255, 65025),
)

Uruchamianie testów

Mając przygotowane testy oraz parametry, możemy przejść do ich uruchomienia. Jedyną modyfikacją przed wykonaniem testów dla konkretnego wariantu jest ustawienie, które parametry wykorzystać. Możemy tego dokonać w pliku parametryzacyjnym lub po prostu  zaimportować plik z innymi danymi parametryzacynymi. W tym celu przed uruchomieniem, należy zmienić import parametrów w pliku  test_calculator.py na jedną z poniższych (odpowiednio dla wariantu A, B i C):

from input_a import input_operation, input_power_function
from input_b import input_operation, input_power_function
from input_c import input_operation, input_power_function

Samo wykonanie testów można uruchomić standardową formułą pytestową:

pytest -v test_calculator.py

Otrzymamy tym samym rezultaty w postaci:

1. Wariant A:

test_calculator.py::test_operation[1-*-10-10] PASSED		            [ 20%]
test_calculator.py::test_operation[10-+-0-10] PASSED              [ 40%]
test_calculator.py::test_operation[5---10--5] PASSED                [ 60%]
test_calculator.py::test_power_function[1-1] PASSED                [ 80%]
test_calculator.py::test_power_function[255-65025] PASSED		[100%]

2. Wariant B:

test_calculator.py::test_operation[1-*-255-255] PASSED                   [ 25%]
test_calculator.py::test_operation[255-+-0-255] PASSED                  [ 50%]
test_calculator.py::test_operation[100---255--155] PASSED              [ 75%]
test_calculator.py::test_power_function[number0-result0] SKIPPED  [100%]

3. Wariant C:

test_calculator.py::test_operation[1-*-255-255] PASSED                 [ 16%]
test_calculator.py::test_operation[255-+-0-255] PASSED                [ 33%]
test_calculator.py::test_operation[100---255--155] PASSED             [ 50%]
test_calculator.py::test_operation[170---32-5.31] PASSED               [ 66%]
test_calculator.py::test_power_function[0-0] PASSED                      [ 83%]
test_calculator.py::test_power_function[255-65025] PASSED          [100%]

Jak widać, dla wariantów A oraz C zostały wykonane wszystkie testy dla zestawów test_operation, test_power_function. Natomiast dla wariantu B, który nie posiadał opcji potęgowania, zestaw testów test_power_function został pominięty.

Wykonując testy w powyższy sposób, w każdym przypadku wykorzystujemy taką samą formułę do uruchomienia testów, a co za tym idzie, nie musimy pamiętać, które testy są odpowiednie dla danego wariantu testowanego urządzenia, gdyż jest to obsługiwane przez plik z parametrami. Dodatkowo w podsumowaniu wykonanych testów podczas analizowania testów oznaczonych jako SKIPPED, łatwo można znaleźć testy, które mogłyby być zaadaptowane do aktualnie testowanej wersji.

close

Newsletter