Próbowałem pisać testy jednostkowe interfejsu użytkownika dla moich aplikacji GUI i mam do czynienia z problemem, że chociaż działają one dobrze, gdy je początkowo piszę, okazują się kruche i pękają przy każdej zmianie projektu (czyli dość często). Próbuję znaleźć zestaw wskazówek, które doprowadziłyby mnie do posiadania możliwych do utrzymania testów jednostkowych dla GUI.
Na razie jedną rzeczą, którą odkryłem, jest to, że testy z informacją „ten składnik powinien gdzieś pokazywać swoje dane wejściowe” są dobre (i to bardzo łatwe w przypadku HTML). Testy sprawdzające określony stan określonej części komponentu są zwykle kruche. Testy typu kliknięcie-kliknięcie-kliknięcie-oczekiwanie, które próbują śledzić zachowanie użytkownika i leżącą u jego podstaw logikę biznesową (która jest najważniejszą częścią), zwykle okazują się kruche. Jak napisać dobre testy?
Mówiąc ściślej, chciałbym poznać pewne wzorce dotyczące tego, co mogę przetestować w moim interfejsie użytkownika, a nie dokładnie, jak to przetestować. Konwencje nazewnictwa i stałe identyfikatory są dobre, ale nie rozwiązują podstawowego problemu, jakim jest to, że GUI bardzo się zmieniają. Chciałbym przetestować zachowania, które najprawdopodobniej się nie zmienią. Jak znaleźć właściwą rzecz do przetestowania?
Odpowiedzi:
Typowy problem z testami GUI ... Głównym powodem, dla którego testy te są uważane za kruche, jest to, że nie mogą one przetrwać zmiany GUI, która nie jest zmianą wymagań . Powinieneś dążyć do takiej struktury kodu testowego, aby zmiana w GUI była izolowana w jednym miejscu w testach.
Jako przykład rozważ test o treści:
Tutaj jest dużo miejsca na przerwanie tego testu po przerobieniu interfejsu, nawet jeśli wymagania dotyczące sprawdzania poprawności pozostaną.
Dodajmy teraz trochę alternatywnego sformułowania:
Test jest taki sam, wymagania są takie same, ale ten rodzaj testu przetrwa przeróbkę interfejsu użytkownika. Oczywiście będziesz musiał zmienić kod, ale kod zostanie odizolowany. Nawet jeśli masz dziesięć lub dwadzieścia takich testów dla swojej strony profilu i przenosisz logikę sprawdzania poprawności wyświetlającą błędy z alertów javascript do wyskakujących okienek, na przykład wystarczy zmienić tylko jedną część testową, która sprawdza komunikaty o błędach.
źródło
To jest powszechny problem. Chciałbym zwrócić uwagę na:
Jak nazywasz elementy
Użyj identyfikatora css lub klasy, aby zidentyfikować elementy. Preferuj używanie identyfikatora CSS, gdy obiekt jest unikalny. Zastanów się, jakiej ramy używasz, na przykład w Ruby on Rails
name
atrybut ten jest przypisywany automatycznie i może (nie intuicyjnie) być lepszy niż użycie css id lub klasyJak rozpoznajesz elementy.
Unikaj identyfikatorów pozycyjnych, takich jak
table/tr/td/td
na przykład formytd[id="main_vehicle"
lubtd[class='alternates']
. W razie potrzeby rozważ użycie atrybutów danych. Jeszcze lepiej staraj się unikać znaczników układu, takich jak w<td>
ogóle, więc w powyższym przypadku możesz dodać zakres i użyć go, np.<span id="main_vehicle">
Lub selektora symboli wieloznacznych, takiego jak*[id="main_vehicle"]
gdzie*
może być teraz div, span, td itp.Korzystanie z atrybutów danych specyficznych dla testu które są używane tylko do qa i testowania.
Unikaj niepotrzebnych kwalifikacji do elementów. Możesz znaleźć się przy użyciu następujących czynności:
body.main div#vehicles > form#vehicle input#primary_vehicle_name
Wymaga to jednak, aby pole wejściowe pozostało w formie z dokładnym identyfikatorem pojazdu i na stronie z treścią, która ma klasę main i div z identyfikatorem pojazdów, które mają bezpośrednie potomek formularza o identyfikatorze pojazd. Wszelkie zmiany w dowolnej z tych struktur i test są przerywane. W takim przypadku możesz to znaleźć
input#primary_vehicle_name
wystarczy, aby jednoznacznie zidentyfikować element.
Unikaj testów, które odnoszą się do widocznego tekstu. Tekst na stronie wyświetlany użytkownikowi zwykle zmienia się w czasie, gdy witryna jest utrzymywana i aktualizowana, więc używaj identyfikatorów, takich jak identyfikator css i klasa css lub atrybuty danych. Elementy takie jak
form
,input
iselect
stosowane w formach są również dobre części elementów identyfikujących, zwykle w połączeniu z identyfikatorem lub klasy, npli.vehicle
alboinput#first-vehicle
Można również dodawać własne identyfikatory, np<div data-vehicle='dodge'>
. W ten sposób można uniknąć używania identyfikatorów elementów lub klas, które mogą zostać zmienione przez programistów i projektantów. Z czasem odkryłem, że lepiej jest po prostu współpracować z programistami i projektantami i dojść do porozumienia co do nazw i zakresów. To jest trudne.Jak utrzymywane są stałe dane.
Podobnie jak w przypadku identyfikowania rzeczywistych elementów, staraj się unikać wbudowanych na stałe selektorów identyfikujących wartości na korzyść obiektów strony - małych fragmentów tekstu, które są przechowywane w zmiennych lub metodach, a zatem mogą być ponownie użyte, a także przechowywane centralnie. Przykłady zmiennych javascript zgodnie z tym wzorem dla wartości zakodowanych na stałe:
Więcej na temat obiektów stron na selenium wiki i dokumentach selenium
Komunikacja z programistami.
Niezależnie od technicznego podejścia w zakresie „programiści wprowadzają zmiany i łamią automatyzację kontroli jakości”, to jest problem z przepływem pracy. Musisz upewnić się, że: każdy jest jednym zespołem; programista przeprowadza te same zintegrowane testy; standardy są uzgadniane i przestrzegane przez obie grupy; definicja gotowego obejmuje uruchomienie i ewentualnie aktualizację testów interfejsu użytkownika; programiści i testerzy łączą plany testowe i oboje uczestniczą w pielęgnacji biletów (jeśli wykonują Agile) i rozmawiają o testowaniu interfejsu użytkownika w ramach pielęgnacji. Powinieneś upewnić się, że wszelkie podejście i strategia używane do nazewnictwa są skoordynowane z twórcami aplikacji. Jeśli nie znajdziesz się na tej samej stronie, polubisz nazewnictwo obiektów. Kilka przykładów metod obiektów strony, które niedawno stworzyłem dla projektu ruby:
Oto te same obiekty stron, co zmienne javascript:
źródło
Powodem, dla którego ludzie opracowali takie rzeczy jak MVC, MVP i prezenter oraz podobne wzorce projektowe, było oddzielenie logiki biznesowej od interfejsu użytkownika.
Oczywiście część widokową można przetestować tylko poprzez uruchomienie programu i sprawdzenie, co pokazuje - innymi słowy, można ją przetestować tylko w testach akceptacyjnych.
Z drugiej strony testowanie logiki biznesowej może odbywać się w testach jednostkowych. I to jest odpowiedź na twoje pytanie. Przetestuj wszystko w modelu, a jeśli możesz i chcesz, możesz również przetestować kod kontrolera.
Może się to zdarzyć tylko wtedy, gdy zmienisz wymagania. Gdy wymaganie się zmienia, nie można go obejść, poza modyfikacją kodu. Jeśli uda Ci się stworzyć dobry projekt i architekturę, zmiana nie pojawi się w wielu miejscach.
źródło
Testy interakcji GUI nie powinny być mniej lub bardziej kruche niż jakiekolwiek inne testy. To jest; jeśli aplikacja zmienia się w jakiś sposób, testy muszą zostać zaktualizowane, aby to odzwierciedlić.
Dla porównania:
Test jednostkowy
Oryginał :
validateEmail()
powinien zgłosićInvalidData
wyjątek. Co zostało poprawnie uwzględnione w teście jednostkowym.Zmień :
validateEmail()
powinien zgłosićInvalidEmail
wyjątek. Teraz twój test jest niepoprawny, aktualizujesz go, a wszystko znów jest zielone.Test GUI
Oryginał : Podanie nieprawidłowego adresu e-mail spowoduje wyświetlenie wyskakującego okna błędu zawierającego „Wprowadzono nieprawidłowe dane”. Prawidłowo wykryty przez twoje testy.
Zmiana : Podanie nieprawidłowego adresu e-mail spowoduje powstanie błędu wbudowanego zawierającego „Wprowadzono nieprawidłowy adres e-mail”. Teraz twój test jest niepoprawny, aktualizujesz go, a wszystko znów jest zielone.
Pamiętaj, że testujesz dane wejściowe i wyjściowe - niektóre dobrze określone zachowania. Niezależnie od tego, czy jest to test GUI, test jednostkowy czy test integracji itp.
źródło