BDD
Behavior-driven development : proces wytwórczy oprogramowania który powstał na podstawie procesu Test driven development TDD.
Zgodnie z metodyką TDD, dla każdej jednostki oprogramowania programista musi:
-najpierw zdefiniować zestaw testów dla danego modułu;
-doprowadzić do niezaliczenia testów;
-zaimplementować moduł;
-na końcu upewnić się, że wdrożenie modułu sprawiło, iż testy zostały wykonane pomyślnie
(przykład zadania TDD LINK )
Ta definicja jest raczej niespecyficzna, z tego powodu, BDD można postrzegać jako ciągły rozwój TDD, który dokonuje bardziej szczegółowych wyborów niż TDD.
BDD określa, że testy dowolnej jednostki oprogramowania powinny być opisane pod kątem pożądanego zachowania urządzenia (pożądanego zachowania oznacza : ma wartość biznesową dla dowolnego podmiotu, który zlecił stworzenie danej jednostki oprogramowania )
BDD to połączenie wspólnych metod i zasad TDD z cechami procesu domain-driven design
(DDD - podejście do tworzenia oprogramowania kładące nacisk na takie definiowanie obiektów i komponentów systemu oraz ich zachowań, aby wiernie odzwierciedlały rzeczywistość, zaleca stosowanie wzorców projektowych ).
BDD skupia się na następujących aspektach:
-Od czego zacząć w procesie
-Co testować, a czego nie testować
-Ile można przetestować za jednym razem
-Jak nazwać testy
-Jak zrozumieć przyczynę ewentualnego niepowodzenia testu
Głównym celem BDD jest ponowna analiza podejścia testów jednostkowych i akceptacyjnych, które naturalnie pojawiają się w tych kwestiach.
Przykładowo, BDD sugeruje, aby nazwy testów jednostkowych były całymi zdaniami zaczynającymi się od warunkowego czasownika (np. w języku angielskim - od czasownika "should" - "powinien") i powinny być pisane w kolejności ich wartości biznesowej.
Testy akceptacyjne powinny być napisane za pomocą tzw. "historyjek użytkowników" o następującej strukturze: "jako [rola] chcę [opis oczekiwanej funkcji], aby [opis oczekiwanej korzyści]".
Kryteria akceptacyjne powinny być pisane w kategoriach scenariuszy i zaimplementowane w postaci klas: Given [początkowy kontekst], When [opis występującego zdarzenia], then [potwierdzenie wystąpienia oczekiwanego rezultatu] .
Od tego momentu wiele osób opracowało ramy BDD przez kilka lat, definiując je ostatecznie jako platformę komunikacji i współpracy dla programistów, testerów i nietechnicznych lub biznesowych uczestników projektu.
INSTALACJA Behave:
Na Wsl:
Instalacja:
sudo apt install python3 python3-pip ipython3
Lokacja:
which python3
Start:
python3
dostęp do dysku C windowsa na WSL:
cd /mnt/c/
lub folder domowy (cd ~ ) ubuntu dostęp w windows:
C:\Users\marcin.belzowski2\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu18.04onWindows_79rhkp1fndgsc\LocalState\rootfs\home\user
pip:
sudo apt install python-pip
behave:
pip install behave
sudo apt install python3-behave
Na Windows:
MS Store zainstaluj Windows Terminalhttps://www.python.org/downloads/
where python3 - wskaże folder instalacji (ale działa tylko z cmd nie powershel)
python - uruchomi
polecane IDE: https://www.jetbrains.com/pycharm/
pip:
instaluje się razem z pythonem3
behave:
pip install behave
Behave:
Step definition:
w projekcie w folderze "steps".
to funkcje pythona defioniowane jako dekoratory
https://chyla.org/blog/Python_-_Dekoratory/
zaczynają się @given , @then, @when
może być więcej plików .py, nie będą steps ale mogą zawierać funkcje importowane przez steps
Struktura plików:
zawartość pliku test_case_1.feature:
Feature: Test Cases Group 1 Scenario: Running Test Case 1 Given I am the main directory Then I should also be in the main directory
identycznie case 2 tylko zamiast 1 jest 2.
Zawartość pliku steps.py
from behave import given, when, then # import login from login import login @given("I am the main directory") def in_main_dir(context): print("1111111") print("1111111") print("1111111") @then("I should also be in the main directory") def also_in_main_dir(context): pass
uruchamianie 1 pliku:
> behave test_case_1.feature
uruchamianie z printoutem:
> behave test_case_1.feature --no-capture
zasady uruchamiania:
.
pliki testu i folder Steps muszą być w tym samym folderze. Jeśli pliki testu są w podfolderze wtedy w pliku steps.py trzeba zainportować ten folder (np folder "login" )
from login import login
zaby uruchomić test będąc w (pod)folderze login (i wykorzystać steps.py który jest w folderze powyzej) steps.py musi zawierac:
import login (bo startujemy juz z tego folderu więc nie potrzeba "from login")
co ważne nasz dodany (pod)folder login (który jest na tym samym poziomie co steps- zaburza zasade) nie może mieć wewnątrz swojego folderu "steps" jeśli by miał, behave nie będzie szukał tego folderu powyżej.
Uruchamianie wielu plików na raz:
>behave
Moduły:
jeśli jakiś folder ma być traktowany jako moduł, musi zawierać plik
__init__.py (dwa podkreślenia przed i po)
Wyświetlanie na konsoli:
Standardowo ustawione jest logowanie, jeśli chcemy wyświetlić na konsoli dodaj --no-capture
ale jeśli będziemy mieli błąd, to wyświetli na cout na konsoli!
Przykład (fragment pliku steps.py)
@then("I should see 'Preferences'") def see_prefernces(context): print("Should see preferences") assert 1 == 2, "one is not same as two"
powyższa asercja nie spełnia warunku, powstaje błąd, jak widać spowoduje wyświetlenie stdout (Captured stdout: ) nawet bez parametru --no-capture
Dwa pierwsze przeszły (I am the home page, I click on my account - zielone) I should see 'Preferences - nie przeszło
w takim przyadku dodanie --no-capture, spowoduje klasyczne wyświetlenie coutów w miejscu ich wystąpienia, nie zbiorowo pod Captured stdout:
Given’, ‘Then’, ‘When’, ‘And’, ‘But’
given - wstępne warunki, ustawianie akcji, bez interakcji
when - interakcja z aplikacją, działanie na czymś
then - weryfikacja, oczekiwanie
and&but - reprezentują poprzednie słowo kluczowe
Passing Parameters to Steps
Jeśli chcemy by jedno słowo było definiowaną zmienną ( tu French) wygląda to tak:
i wtedy zawartość pliku feature wygląda następująco:
Feature: Test Cases Group 1 Scenario: Running Test Case 1 Given I go to the "English" version of the site
a kod pliku steps wygląda następująco:
@given("I go to the {lang} version of the site") def go_to_site_version(context, lang): print("The language is: {}".format(lang))
Ważne, aby poprawnie wyświetlał printy uruchamiaj
na Windows:
behave --no-capture
na Linux:
behave --no-capture -f plain
inne przykłady kodu:
@then('I should see "{txt}"') def i_should_see_text(context, txt): if txt not in ['success', 'error']: //1 raise Exception("Unexpected text passed in.") if txt.lower() == 'success': //2 print("Yeyyyyyyy") else: print("NOOOOOOOOOO")
//1 jeśli zmienna txt podana w pliku feature:
Feature: Passing parameters to steps Scenario: method 1 of passing step parameters Then I should see "errrrror"
nie zawiera się w ['success', 'error'] podnieś wyjątek, spowoduje to Fail i wyświetlenie coutów
//2 jeśli txt pomniejszony do małych liter równa się success wyświetl...
wyświetlanie typu zmiennej qty, zmiana typu:
print (type(qty))
new_qty = int(qty)
print (type(new_qty))
Sharing Data Between Steps
tworzymy zmienna dostępną globalnie(za pomocą context- instancja klasy behave):
ostrożnie z używaniem zmiennych, możesz sprawdzić czy twoja zmienna znajduje się w context
>>>'your_var' in context
przykład dostępu do wspolnej zmiennej ( context.order_num )przez kolejne kroki:
@given('I find recent order from database') def find_order_from_db(context): print("Finding an order from the database....") context.order_num = '112233' print("Found an orders. Order number: {}".format(context.order_num)) #----------------------------------------------------------------------------------------------------------------------# @when('I issue a refund for the order') def issue_refund(context): print("Trying to issue a refund for order number: {}".format(context.order_num))
Practical Examples
Jeśli mamy projekt/folder i w nim folder z modułami np: BDDCommon, który ma podfoldery (3 x Common...)
to, żeby zawartości tych folderów mogły być importowane jako moduły to:
- muszą zawierać pusty plik o nazwie __init__.py
- w głownym projektu folderze musi być plik który określa packkages=
tu setup.py
setup.py
from setuptools import setup setup(name='PythonBDDtutorial', version='1.0', description='Python BDD Practical Examples', author='name', author_email='ad@...', url='https://www.', packages=[ 'BDDCommon', 'BDDCommon.CommonFuncs', 'BDDCommon.CommonSteps', 'BDDCommon.CommonConfigs' ], )
żeby stworzyć w Pythonie opisane powyżej moduły (3 x Common...) trzeba je zbudować.
$ python setup.py install
Po każdej zmianie trzeba ponownie budować, można dać: python setup.py develop
wtedy automatycznie jest tworzone po każdej zmianie.
Foldery które tworzy to widoczne na rysunku folderów:
build
dist
PythonBDDtutorial.egg-info
żeby potem zaimportować w oryginalnym pliku steps.py dodajemy:
#from behave import given, when, then from BDDCommon.CommonSteps.webstepscommon import * from BDDCommon.CommonConfigs import locatorsconfig from BDDCommon.CommonFuncs import webcommon @then('the "{nav_bar}" bar should be visible') def verify_nav_bars_visible(context, nav_bar): ....
zainstaluj:
1) firefoxa
2)
pip install -U selenium
3)
https://github.com/mozilla/geckodriver/releases
dodaj zmienną PATCH do geckodrivera i zresetuj windows
uruchom behave (folder steps w test) ale nie działa z wsl (brak mozliwosci uruchomienia przeglądarki) działa z PowerShell i CMD windows.
Konfiguracje
Dodaj folder w packages (tu w pliku setup.py który po zmianie przeładować python setup.py install
packages=[ 'BDDCommon', 'BDDCommon.CommonFuncs', 'BDDCommon.CommonSteps', 'BDDCommon.CommonConfigs'
następnie w pliku steps.py zaimportuj plik tu locatorconfig
from BDDCommon.CommonConfigs import locatorsconfig
przykladowe konfiguracje w pliku locatorconfig:
LOCATORS = { 'main navigation' : {'type': 'id', 'locator':'mainnav'}, 'top navigation' : {'type': 'id', 'locator':'top'}, 'options' : {'type': 'css selector', 'locator':'.options-bar'} } URLCONFIG = { 'python.org': 'https://www.python.org/ ' }
Setup - Teardown
przed i po Feature, Scenario, Step.
Background
słowo kluczowe jak Feature, tyle, że jeden Background na featurefile
Scenario Outlines
żeby poniższy przykład działał uzyj słowa kluczowego: Scenario Outlines
dwa scenariusze:
i więcej:
Przyklad:
steps.py
from behave import given, when, then @given("I login as a new user") def login_as_new_user(context): print("I am logged in as a new user. ") @when('I add a "{state}" shipping address') def add_shipping_address(context, state): print('Adding address in state: {}'.format(state)) @when("I add a $40 book to the cart") def add_book_to_cart(context): pass @then("tax should be calculated") def tax_should_calculate(context): pass
scenariu_outline_demo.feature
Feature: example/demo of scenario outline Scenario Outline: Users in with shipping address in <state> should get charged sales tax Given I login as a new user When I add a $40 book to the cart And I add a "<state>" shipping address Then tax should be calculated Examples: | state | | CA | | NY | | TX |
Wynik 3 różnych scenariuszy:
Tags
Przykład pliku feature:
@regression Feature: Navigation panels in home page @smoke Scenario: The home page should have all navigation panels Given I navigate to the home page Then I should see all navigation panels @smoke Scenario: The left navigation panel should have all options Given I navigate to the home page Then the left navigation panel should have all options Scenario: The top navigation panel should have all options Given I navigate to the home page Then the top navigation panel should have all options
uruchamianie Tagów:
uruchomienie z tags smoke uruchomi tylko scenaiusze z tagami smoke.
wynik: od góry bez tagów, dolna połowa z tagiem "smoke"
łączenie Tagów:
Przykłady LINK:
Udemy Kurs
https://tohtml.com/




















