Cześć, dawno mnie tu nie było. Pisałem ostatnio kilka wpisów dla testuj.pl również będą się tam pojawiać od czasu do czasu moje wpisy, więc zachęcam was do sprawdzania serii o SpecFlow (link).
Dzisiaj zajmiemy się tematem – testowaniem treści mail. Tworząc test automatyzujący akcje, które musielibyśmy zrobić.
Jak podejść do testowania automatycznego maili, które przychodzą na skrzynkę mailową?
W czystym Selenium jest to możliwe jednak nie, jest to proste jak z narzędziem, które pokażę wam dzisiaj. Z pomocą przychodzi nam Maliosaur. Nie użyjemy dziś Selenium więc nasz test będzie testował funkcjonalne, ale poprzez dostęp do API Mailosaura, które ma napisanego klienta dla .NET-u (Stworzony został wrapper API dla .NET-u)
Testowanie automatyczne zapomnianego hasła lub innych mail z systemu?
Naprawdę może być prostsze.
Czego potrzebujemy?
Visual Studio 2017;
Stworzenie konta na mailosaur – W wersji trial możemy korzystać z konta przez 14 dni;
SpecFlow – nie jest niezbędny, ale nasz przykład będzie korzystał z niego;
R# – nie jest niezbędny, ale używam go do uruchamiania testów, oczywiście może również być NUnit Console Runner;
Testowa strona – w moim przypadku jest to WordPress, ale może być dowolna inna strona, która interesuje was.
Zaczniemy od utworzenia projektu typu class library w Visual Studio 2017. Tworzymy strukturę katalogów:
Struktura katalogów naszego projektu
Mailosaur korzyści:
Przyjazne API, które pozwala testować nam poprawność treści mail (HTML), linki do obrazków wraz z podpisem, zgodność nadawcy, adresata lub adresatów
Szybciej napiszemy test dla formularzy takich jak przypominanie hasła niż standardowo w Selenium WebDriver.
Czas -taki test może trwać kilka – kilkadziesiąt sekund zależnie od złożoności. Test UI zająłby więcej czasu.
Po dodaniu folderów dodajemy do NuGet Packages
Mailosaur 3.0.2
HtmlAglityPack 1.7.0
SpecFlow 2.3.0
NUnit 3.9.0
Nasz scenariusz będzie sprawdzał, czy mamy w naszej skrzynce maila tytułem “Welcome to WordPress.com”. W kolejnym kroku sprawdzał, będzie czy nadawca, oraz odbiorca zgadzają się z tymi, które zakładaliśmy. W tej metodzie również dokonujemy asercji priorytetu maila oraz czy dobry jest host nadawcy.
W następnym kroku sprawdzimy, czy obrazek, który powinien być w tym mailu jest, wraz z adresem i podpisem do niego. W ostatnim kroku dokonamy sprawdzenia poprawności html maila, który do nas przyszedł zgadza się z tym co byśmy sami zaimplementowali. W tym ostatnim kroku porównamy te dwa html. Jeden to będzie html wzięty z maila, drugi nasz, który napisalibyśmy lub mieli jego implementacje (W naszym przypadku WordPress zrobił to).
Listing – Scenariusz EmailsInWordpressFeature
SpecFlow Feature – Scenariusz, który zaimplementujemy
Zaczynamy.
Przechodzimy do dodania naszego scenariusza do folderu Features. Plik nazywam jako EmailsInWordpressFeature.feature
Następnie dodajemy klasę EmailSteps w niej będą znajdywać się wszystkie potrzebne kroki.
1) Krok – “I check view of “<Subject>” mail
Listing – EmailSteps – zawierająca wszystkie potrzebne kroki w naszym scenariuszu
EmailSteps.cs – wszystkie kroki
EmailsSteps – konstruktor
Rozpoczynamy od dodania dziedziczenia po klasie BaseStep. Jest to klasa pomocnicza, która zawiera pola protected, które używamy w klasie EmailSteps.
BaseStep – klasa bazowa z, której dziedziczy nasza klasa kroków
Wracamy do naszego pliku EmailSteps. Zaczynamy od zdefiniowania potrzebnych parametrów w konstruktorze i inicjalizacji ich.
Kolejnym krokiem jest utworzenie metody GivenICheckViewOfMail dla kroku -> “I check view of “”(.*)”” mail”.
W linijce [23] korzystamy z klasy MailosaurHelper
MailosaurHelper
zawierająca metodę TakeEmails(), która zwraca maile dla naszego maila. Nasz mail mamy zdefiniowany w klasie TestSettings (implementacja niej). Dodatkowo dodajemy metodę Single(), która zwróci nam mail z określonym tematem. Używamy metody Single() dlatego, że spodziewamy się tylko i wyłącznie jednego maila z tym tematem, więc jeżeli byłoby więcej maili o tym tytule to aplikacja w tym miejscu zwróci błąd.
W linijkach [24-25] klasy EmailSteps korzystamy z EmailContext’u.
I check correctness of html codeEmailContext – przechowywanie wartości pomiędzy krokami
Jest to klasa, która zawiera wszystkie potrzebne właściwości z, których będziemy korzystać w całym projekcie. ScenarioContext pozwala przechowywać różnego typu wartości podczas testu i mieć do nich dostęp pomiędzy krokami. Kod jest znacznie przyjemniejszy do utrzymywania, gdy korzystamy ze wstrzykiwania zależności w kodzie. Dodatkowo uruchomienie naszych testów w sposób współbieżny byłoby dość łatwe, bo korzystamy w tym miejscu z Context Injection.
Na marginesie: Jeżeli korzystalibyśmy ze statycznej klasy ScenarioContext.Current to kod nie będzie działaj współbieżnie. Spowodowane jest to tym, że SpecFlow ma problem (i słusznie) z rozpoznaniem o, który Current nam chodzi. Lepiej korzystać z Context Injection.
W linijce [26] klasy EmailSteps kończymy metodę asercją, która sprawdza, czy temat maila zgadza się z tym, który przekazaliśmy w kroku.
We właściwości MailBox przekazujemy nasz mailBoxId oraz secretKey.
2) Krok – “I check:”
SpecFlow feature – Metoda “I check”
EmailRow
Metoda GivenICheck korzysta z możliwości mapowania rekordu tabeli na obiekt w SpecFlow (Opisywałem to szerzej dla testuj.pl – link). Metoda CheckBasicInfo jako parametr przyjmuje listę wierszy, które mieliśmy w tym kroku. EmailRow jest klasą pomocniczą, aby zmapować poszczególne wiersze tabeli.
W klasie MailosaurHelper dodajemy metodę CheckBasicInfo, która będzie sprawdzać te podstawowe dane przekazane z tabeli. Krok “I check: ” korzysta z niej w linijce [33] pliku
Metoda CheckBasicInfo
Metoda dokonuje asercji, czy w liście, która zawiera wartości z wierszy tabeli, tą, którą przekazaliśmy zgadz nam się adresat, nadawca, oraz priorytet wysyłanej wiadomości i senderHost. Używamy w linijce [28] asercji emailContext.CurrentEmail.To[0].Address, ponieważ spodziewamy się jednego adresata. Jeżeli chcielibyśmy sprawdzić sytuacje z większą ilością adresatów to w tym miejscu trzeba byłoby np. wylistować wszystkich i dodać metodę, która dokona asercji warunku jakiego chcieliśmy.
Krok 3 ) “I check correctness of images on mail: “
Listing – CheckImages metoda, która sprawdza poprawność źródła (Src) oraz podpisu (alt) dla obrazu /obrazów
Krok w EmailsInWordpressFeatureKroki “I check correctness of images on mail: ” w EmailSteps
EmailImage jest to klasa pomocnicza dla parsowania wiersza tabeli na obiekt. W pierwszej kolumnie podajemy adres do obrazka w drugiej podpis, jeżeli jest
EmailImage – klasa używana dla mapowania tabeli – sprawdzanie poprawności adresu oraz podpisu do obrazków.
Metoda CheckImages(emailIamges) która sprawdza, czy url (lub url, bo parametrem jest List<EmailImages> emailImages)
Metoda CheckImage
i podpis do obrazka, który podaliśmy w tabeli znajduje się w mailu, który chcemy sprawdzić. Używamy SingleOrDefault(), bo spodziewamy się tylko i wyłącznie jednego elementu, ale przyjmujemy również, że wyniki tej kwerendy może zwrócić nulla. Dlaczego tak? Dlatego, że w asercji sprawdzamy, czy ten obiekt jest nullem. Możemy dodać zdefiniowany komunikat do tej asercji i może powiedzieć nam to więcej. Np. “We ‘re expecting contain image” może nam to pomóc w debugowaniu. Moglibyśmy również użyć metody Single(), wtedy, jeżeli tego elementu by nie było to test podczas uruchomienia zwróciłby wyjątek “Sequence contains no elements”. W tym miejscu użyłem tego drugiego sposobu. Chce wam pokazać, że mamy przynajmniej dwie możliwości podejścia do tego typu sytuacji. Zachęcam żebyście wybrali tą, która wam bardziej pasuje. Assert.IsNotNull z dodatkowym komunikatem może przekazywać bardziej trafioną informacje niż “Sequence contains no elements”.
Krok 4 ) “I check correctness of html code”
I check correctness of html code
Listing – CompareHtml metoda porównująca dwa html
Klasa TestSettings zawiera mail, którego używamy w teście oraz ścieżkę do pliku html dla formularza powitalnego WordPressa
TestSettings – klasa zawierająca podstawowe ustawieniaMetoda CompareHtml
CaptureHtml jest to metoda, która przyjmuje dwa parametry. Pierwszy to string, który ma być w domyślnie przekazanym html a drugi parametr również string, ale używany do wskazania gdzie nasz plik tekstowy z html się znajduję. Html Agility Pack (Dodaliśmy przez NuGeta), którego używamy posiada m.in. te dwie możliwości wczytania html z pliku oraz ze zmiennej typu string.
Wczytujemy do dwóch zmiennych html i w linijce [41] porównujemy asercją czy zgadzają się oba html. Używamy tutaj dodanej właściwości w klasie TestSettings – PathHtmlWelcomeTxt.
Naszym oczom ukazuje się czas wykonania testu niecałe trzy sekundy.
Podsumowanie
Dzisiaj dowiedzieliśmy się w jak (dość) prosty sposób testować treści wysyłanych przez nas mail. Wiem, że są serwisy, które posiadają kilkadziesiąt typów różnego rodzaju maili, więc takie rozwiązanie może być znacznym ułatwieniem pracy w zespole oraz unikanie regresji. Jeżeli korzystacie np. z MailGuna to on, również posiada przyjemne API, które proste jest do zautomatyzowania. Zachęcam do udostępniania treści i podzielenia się jak wy testujecie wasze maile.
Michał Ślęzak
Test Development Engineer w Sii. Szuka miejsc, gdzie automatyzacja może pomóc. Lubi prowadzić prezentacje i warsztaty związane z automatyzacją testów. Mail kontakt@testingplus.me
Ta strona korzysta z ciasteczek aby świadczyć usługi na najwyższym poziomie. Dalsze korzystanie ze strony oznacza, że zgadzasz się na ich użycie.Zamknij