Czego szuka QA na konferencji programistycznej?

Pomiędzy wierszami.

Mija pierwszy dzień po powrocie do pracy i wciąż czuje odmienny stan umysłu po konferencji Devoxx. Rozmowa z kolegą podczas podróży do firmy, dyskusje w kuchni z ludźmi z zespołu – widać, że jest o czym opowiadać. Oczywiście zawsze pada pytanie po co? Przecież w zaciszu domowym każdy może włączyć wideo z dowolnej prelekcji i… chyba na tym kończą się podobieństwa do analogowej konferencji. Stąd też pomysł aby opisać jakie wartości może odkryć QA jadąc na konferencję programistyczną pomijając opis mięsa zawartego w prelekcjach dotyczącego tooli, praktyk i wszystkiego co można wyszukać w domowym zaciszu. Okazuje się, że poza serią prezentacji konferencja ma sporo do zaoferowania.

 

Klasycznie – na prelekcjach20150622_085854

Na początek standardowo – wjazd na otwierające przemówienie. Devoxx zaczą sie z przytupem – porywający wykład na sali wypełnionej po brzegi, gdzie prelegent czaruje publiczność. Podobało mi się bycie elementem tłuszczy zabawianej heheszkami z poważnych problemów. Mózg QA działa wielowątkowo więc po za wchłanianiem treści miała miejsce analiza tego co stanowi o tym, że dostarczona prezentacja jest dobra, że wywołuje emocje i ludzie wychodzą zadowoleni. Czy tak powinno wyglądać też praca w zespole? Czy z taką pasją powinniśmy podchodzić do projektu? Mówić o ważnych sprawach jednocześnie zapalając ludzi do działania? A może to tanie show i szarlatańska manipulacja wysysająca z nas $$$?

Miękki temat openingu łatwo wchodził w głowę – warto zauważyć: zawsze znajdzie się ścieżka prelekcji dla mniej technicznych osobników traktująca o rozwoju, zarządzaniem zespołem, rozwiązywaniem problemów w projektach – jeśli nie masz super programistycznych skillów nic nie szkodzi, z pewnością znajdziesz coś dla siebie.

Dałem się porwać atmosferze z openingu i natchniony popędziłem ku następnym wykładom. Przy okazji popełniłem błąd – nie notowałem kluczowych rzeczy które mnie zainteresowały – stwierdziłem i tak będzie w necie… ale, po co tracić czas oglądając to samo, i dodatkowo warto na gorąco przeanalizować temat, a materiały z imprezy pojawiają się ze sporym opóźnieniem – lesson lerned.

 

Co tam panie w manufakturach słychać

CIRN0aOUEAEezwI
twit od DevoxxUK

Na terenie budynku, w którym odbywała się konferencja, rozstawionych było około 20 firm. Przerwy pomiędzy prelekcjami postanowiłem wypełnić najazdem na stoiska i rozmowami na temat pracy QA i rozwiązań około testerskich w projektach w danych firmach. Po pierwsze okazuje się, że jest sporo ludzi z zagranicy więc kontakt w języku angielskim – ta niepewność w podbijaniu do stoiska i wyborze języka komunikacji:) Kolejną ciekawą rzeczą okazuje się, że firmy różnie podchodzą do obsady swoich stoisk. Czasem są to rekruterzy, marketingowcy, czasem programiści, QA itd. Nie ma więc pewności czy trafisz na osobę ogarniętą w temacie QA w projektach.

Dla przykładu panie z ZALANDO opisywały pracę bardzo wysokopoziomowo. Z ich wypowiedzi płyną jasny przekaz – pracują u nas testerzy ale to są programiści z taką rolą projektową. Gdy wymaga tego sytuacja testerzy maja też wykonywać taski deweloperskie 🙂 Cenna uwaga – QA dla niektórych to mocny koder 😀 Podobnie w JLABS, też nie ma typowych stanowisk testerskich (chyba, że UX) – programiści dbają o jakość aplikacji, osoby od zbierania wymagań weryfikują wprowadzone funkcje, testerami są też użytkownicy końcowi i szybki deploy aplikacji. Widać trend jak najszybszego wypychania apek na produkcję.

W SPARTEZ mają inną wizję QA – jeden na cały zespół. Dla członków zespołu jest on mentorem który dba o krzewienie nawyków związanych z jakością. Uczy zespół aby nie skupiać się wyłącznie na dostarczeniu funkcji z notki ale również na wysokopoziomowym celu swojej pracy, zadowoleniu użytkownika i dbaniu o rozwiązanie wolne od błędów. QA to gość który usprawnia cały proces, dostrzega ryzyka i minimalizuje prawdopodobieństwo wypuszczenia niepoprawnie przetestowanego softu – co nie oznacza, że to on ma ten soft testować…

W kolejnych firmach QA byli standardowo odpowiedzialni za automatyzację, często z wykorzystaniem cucumberopodobnych frameworków. Widać mocny nacisk na programowanie. Pytając o testerów w firmie standardowo odpowiadano, że nie robią testów manualnych ale za to posiadają automatyków, inżynierów jakości czy QA. Oczywiście standardowy opensourcowy stos – Selenium, Phantom opakowany we własne rozwiązania odpalane na CI. Czasem integracja z jakąś chmurą jak browserstack czy bardziej egzotyczne frameworki jak Spock. W TIETO są dedykowane zespoły do projektowania testów, i jako jedyni przyznali się do korzystania z komercyjnego kombajnu do testów – w tym przypadku z QTP od HP (z własnym modułem do testów z Selenium). Jeśli chodzi o BDD spięte z testami end2end to wiele zespołów miało problem z utrzymaniem sporej (> 1000) liczby tego typu testów. Pojawił się temat usuwania i pozostawienia najważniejszych przypadków. Ciekawostką było dążenie do ratio 1:4 w liczbie testerów na programistów w firmie 4FINANCE (no i fajnie było usłyszeć, że można popracować z takimi gwiazdami jak Jakub Nabrdalik czy Tomasz Nurkiewicz) .

Na niektórych stoiskach nie spotkałem osób związanych z QA ale i tak warto było pogadać. Najbardziej utkwiła mi w pamięci rozmowa z wdrożeniowcem z POIVOTAL, opowiadał o tym jak zrezygnowano w jego firmie z ocen rocznych na rzecz super szybkiego feedbacku. Taka ciągła komunikacja relatywnie wyklucza potrzebę kompleksowej oceny rocznej gdyż lider zespołu zna mocne i słabe strony pracownika. Kolejnym tematem była praca w parach. Główne przesłanie było takie: paruj się ile możesz, rozbijaj silosy i dziel wiedzę. Parowanie się również ma sens gdy chodzi o pracę z liderem i innymi osobami. Generalnie jest to ciekawa koncepcja pracy i warto to jakoś zaadoptować.

Bardzo miło zostałem również zaskoczony ilością ofert pracy dla QA – dedykowane ulotki o pracę dla testera spotkałem przy wielu stoiskach co oznacza, że profesjonaliści od jakości są na tyle ważni aby przygotować niezależną ofertę i wydać ulotkę, która będzie współdzieliła przestrzeń z ofertami dla programistów.

Devy bez kagańca…

W zaciszu firmy matki rozmawiamy ale niepoprawne politycznie tematy raczej nie są głośno poruszane. Podczas wieczornych wypadów pomiędzy kolejnymi dniami konferencji można na luzie porozmawiać o wielu sprawach, przedyskutować niewygodne tematy, dostrzec w programistach istoty ludzkie. Niby impreza integracyjna załatwia takie rzeczy ale tu jest się z innego powodu – towarzystwo jest bardziej doborowe, obejrzane pokazy buzują w mózgu i ludzie reagują na taką dawkę odmienności. Zaczyna się dyskusje o tym jak my robimy projekty w porównaniu do tego co zobaczyliśmy na prelekcjach, na jakich obszarach jest dobrze a gdzie jest źle. Ma miejsce nieformalna burza mózgów – co zrobić aby było idealnie, są pomysły, porady, czasem ostra wymiana zdań. Dyskusja była by marna bez QA gdyż wodze fantazji devów niejednokrotnie pomijają znaczenie jakości w wynalezionych złotych rozwiązaniach:)

 

Emocje w służbie działania

?????????????
koszulka od Codewise

Po konferencji oprócz bagażu tooli do przebadania. tony kursów do zrobienia, miliona nowych sposobów na pisanie i testowanie aplikacji przychodzi coś jeszcze (za*%^&te koszulki 🙂 ) – zapał aby tego w końcu spróbować i pomysły jak wykorzystać to w swojej pracy. Nawet, jeśli w obecnym projekcie nie ma na to miejsca, to może w następnym będzie – i wtedy można zrobić mocny wjazd z hipsterskim rozwiązaniem podpatrzonym na konferencji. Dodatkowo motywuje fakt, że QA są bardzo pożądani na rynku, że skille programistyczne coraz bardziej się liczą. To pomaga w ułożeniu w swojej głowie, nad czym należy się skupić, nie tylko w kontekście pracy, ale i rozwoju osobistego. Zaznaczę jeszcze, że oprócz programowania to bliska współpraca z programistami i poprawianie procesu były wyszczególnione w wymaganiach najmocniejszych firm. Oznacz to, że QA na czasie to programista ze skillami miękkimi, który powiedzie zespół ku lepszej jakości.

Podsumowanie

Czy konferencja deweloperska to miejsce dobre dla QA? Dla mnie nie masz wyboru – musisz też stać się programistą aby być dobrym QA, aby poznać problemy, które sprawiają, że jest dla testerów praca, ergo, konferencja jest właśnie dla ciebie:) Dodatkowo spotkasz mnóstwo ludzi z branży i dowiesz się co w trawie piszczy w innych firmach (a także i twojej:)), nabierzesz motywacji i inspiracji do dalszego rozwoju. Dla mnie zawsze są to takie małe lekcje życia, i nie chodzi mi tylko o strefę pracy, dobre praktyki świetnie przekładają się na wsparcie w funkcjonowaniu w społeczeństwie i realizacji planów życiowych.

Devoxx zakończony,  przemyślenia spisane – czas kończyć – trzeba wykorzystać kreatywne pobudzenie i stworzyć coś co zadziwi cały świat.

Do zobaczenia na następnej konferencji:)

 

Testy automatyczne Selenium cz3 – zestawy testów.

AKTUALIZACJA

Najnowszą wersję tego wpisu w formie profesjonalnego (i na obecną chwilę darmowego) kursu znajdziesz na moim autorskim portalu https://jaktestowac.pl/kursy/.
Pozdrawiam Przemek

Wstęp

Wzorując sie na podstawowym teście stworzonym w poprzednim poście http://przemek.yum.pl/testy-automatyczne-selenium-cz2-pierwsze-kroki-w-pythonie/ można napisać kolejne.  Jednak pierwsza asercja, która zakończy się niepowodzenie niestety przerwie cały test i kolejne nie będą już wykonywane – mozna to zuważyć choćby po niezamkniętym oknie przeglądarki.

UWAGA:
Poprzednia wersja tego wpisu był pisana w Python3 obecnie jest w wersji Python2 ze względu na biblioteki do testowania które w przyszłości chciałem opisać. Nie podmieniałem screenów bo są to dość kosmetyczne zmiany. Proszę o wzorowanie się na samym tekście kodu z pisanych przykładów bo te na screenach są w Python3 . Zmiany dotyczą rozwiązania z obsługą kodowania znaków: w Python3 nie jest potrzebna pierwsza linia odnośnie kodowania jak i znaczek u przed apostrofem w stringach (ergo – zastosowano domyślnie rozpoznawanie kodowania znaków specjalnych). Pamiętaj więc o literce u przed każdym łańcuchem zawierającym polskie znaki.Dodatkowo uaktualniłem obecny tytuł strony olx 🙂

Wymagania

Do zbudowania fajnie wyglądającego przypadku testowego należy opanować trochę wiedzy z programowania obiektowego – jednak generalnie zostanie tu wszystko opisane. J Zbudujemy klasę testową która bedzie posiadać metody (warto zapamiętać, że motoda to funkcja znajdująca się w klasie) będące osobnymi przypadkami testowymi.

Jak czegoś nie rozumiesz to na razie się tym nie przejmuj – leć z tutkiem dalej i potem przejdź go drugi raz i wtedy zobaczysz co się rozjaśniło czego trzeba się poduczyć.

Piszemy automat

Na początek tworzę nowy plik z testami   olx_main_tests. Dodaję  linie  umożliwijąca kodowanie polskich znaków oraz importy:

# -*- coding: utf-8 -*-
import unittest
from selenium import webdriver

jak widać będe korzystał z biblioteki unittest, która oferuje wiele przydatnych metod do testowania.

Kodzimy – klasa, pierwszy test i uruchomienie

Deklaruję nazwę klasy korzystając ze słowa kluczowego class:

class OlxMainTests(unittest.TestCase):

korzysta ona z gotowych rozwiązań (dziedziczy) zaimplementowanych w bibliotece unittest
Następnie dodaję metodę która jest właśnie naszym testem korzystając ze słowa kluczowego def (self jest  zawsze dodawane przy metodach):
Dodatkowo nazwę metody zaczynam od słowa test – dzięki czemu zostanie ona rozpoznana jako metoda testowa

def test_main_page(self):

Warto zaznaczyć, że w pythonie o przynależności danego wiersza do danej funkcji decyduje wielkość wcięcia. Dla przykładu powyższa deklaracja metody powinna posiadać jeden tabulator gdyż należy do klasy zdeklarowanej powyżej. To samo z ciałem metody, które  wklejamy z naszego poprzedniego testu – powinno ono zawierać jedno wcięcie pod nazwą metody – czyli efekt końcowy to:

class OlxMainTests(unittest.TestCase):
    def test_main_page(self):
        driver = webdriver.Firefox()
        driver.get('http://olx.pl')
        title = driver.title
        print(title)
        assert title == u'Ogłoszenia - Sprzedam, kupię na OLX.pl'
        driver.close()

Można już uruchomić nowy test (nie zapomnij o nowej konfiguracji uruchumieniowej dla tego testu Run->Run..->Unittest OLxMainTest – gdyż w przeciwnym razie uruchomisz stary test)

Po uruchomieniu widać, że test został rozpoznany i powinien zakończyć się sukcesem
2015-05-03_100032

 

Dodanie kolejnego testu i uruchomienie grupy testów

Dodajemy następny test według posiadanego szablonu – sprawdzimy czy podstrona

'http://olx.pl/oferty/'

zawiera ten sam tytuł co główna. Po za zamianą adresu www należy utworzyć nową nazwę metody:

def test_oferty_page(self):
    driver = webdriver.Firefox()
    driver.get('http://olx.pl/oferty/')
    title = driver.title
    print(title)
    assert title == u'Ogłoszenia - Sprzedam, kupię na OLX.pl'
    driver.close()

Możemy nowy test uruchomić za pomocą nowej konfiguracji uruchomieniowej – jednak czas aby wykonac wszystkie testy razem – klik prawym klawiszem myszki na plik olx_main_tests.py i wybieram Run
Widać, że przeglądarka uruchomiła się dwukrotnie oraz wszystkie testy powinny przejść:
2015-05-03_102503Dodatkowo można rozwinąć drzewko wykonanych testów:
2015-05-03_103114

Następny test i … mamy bug – rozpoznawanie problemu i naprawa testu

Dodam kolejny test – stronę: http://olx.pl/zasady/

ale tym razem ma on nie przechodzić – oto wynik:
2015-05-03_111440Test niestety nie przeszedł. Jak można się zorientować po logu w konsoli – na tej podstronie znajduje się inny tytuł.

Czyżbyśmy znaleźli BUGA!

Ciężko stwierdzić – trzeba by było podpytać twórców aplikacji webowej OLX. Na obecna chwilę zakładam, że taki tytuł ma się wyświetlać więc naprawiam test – i powinno wszystko działać.

(HINT: Jeśli od twórców OLX otrzymałbym odp, że to jest błąd na stronie – wtedy nic nie poprawiam i pozostawiam mój test, który będzie tak długo nie przechodzł jak długo nie zostanie poprawiony błąd)

Refaktoryzacja – przeczyszczamy kod

Jak widać pojawia się sporo powtórzonego kodu – dodatkowo test który nie przeszedł pozostawił otwarta przeglądarkę – co by było gdyby tych testów było 1000?

Uniwersalny kod dla każdego testu w jednym miejscu

Na poczatek dodamy metodę, która wykona się przed każdym testem (umieszczam ją przed wszystkimi metodami):

def setUp(self):
    self.EXPECTED_MAIN_TITLE = u'Ogłoszenia - Sprzedam, kupię na OLX.pl'

Metoda  setUp jest już zaimplementowana w bibliotece unittest link – jedynie rozszerzam jej działanie – dzięki czemu korzystam z tego, że unittest zna tę metodię i uruchamia się ona automatycznie przed każdym testem jednocześnie dodając moje warunki.

W metodzie umieściłem zmienną która przechowuje łańcuch znakowy (nazywamy string). Wielkie litery są użyte aby zaznaczyć, że jest to wartość której nie należy modyfikować poza tą metodą. Użycie self pozwala na dostanie się do tej zmiennej przez inne motody (ponieważ one wszystkie posiadają obiekt self) – czyli w innych metodach gdzie powtarza się wyciągnięty string można wprowadzić zmianę

assert title == self.EXPECTED_MAIN_TITLE

Pamiętaj aby uruchamiać testy po takich zmianach aby sprawdzić czy wszystko działa poprawnie.

Zarządzanie przeglądarką

Natepnie zajmuję zajmuję się zarządzaniem przeglądarką.
Dodaję do metody setUp inicjalizaję drivera

self.driver = webdriver.Firefox()

A w metodach zmieniam linię  z inicjalizacją drivera:

driver = self.driver

Lokalna zmienna w metodzie driver otrzymuje referencję do obiektu self.driver. Można to potraktować jak przypisanie do obiektu wygodnego aliasu  dzięki czemu nie trzeba za kazdym razem używać pełnej nazwy z self. Oczywiście można by było nie dodawac tego aliasu i tylko zmienić driver  na self.driver (gdyż driver jest inicjalizowany w metodzie wywołującej się przed kazdym testem setUp) czyli:

def test_oferty_page(self):
    self.driver.get('http://olx.pl/oferty/')
    title = self.driver.title
    print(title)
    assert title == self.EXPECTED_MAIN_TITLE
    self.driver.close()

Będę się posługiwał formą z aliasem gdyz jest czytelniejsza:

def test_oferty_page(self):
    driver = self.driver
    driver.get('http://olx.pl/oferty/')
    title = driver.title
    print(title)
    assert title == self.EXPECTED_MAIN_TITLE
    driver.close()

W podobny sposób do metody wywoływanej przed kazdym testem setUp pozbywam się wywołania zamykania przeglądarki – dodając na końcu klasy metodę tearDown

def tearDown(self):
    self.driver.close()

Dzięki czemu mozna usunąć ze wszystkich metod wiersz z driver.close()

Testy w jednym oknie przeglądarki

Kolejną sprawę którą można zmienić to uruchamiająca się z każdym testem przegladarka – symulując zachowanie uzytkownika warto (w tym przypadku) zrobić testy na jednej instancji przeglądarki.

Dodatkowo zbadam czas wykonywania się wszystkich testów na osbnych instancjach przeglądarki – przyda się do tego opcja w oknie uruchamiania2015-05-03_124550

klikam trybik i zaznaczam Show Statistic w zależności czy klikniemy na Test Result czy pojedynczy test wyświetli nam się czas wykonania całej grupy bądź poszczególnego testu.

Biblioteka unittest posiada metodę, która uruchomi się tylko raz przed testami dzięki temu można ją wykorzystac do uruchomienia przeglądarki. Przenoszę więć inicjalizajcę Firefoxa do nowej metody

@classmethod
def setUpClass(self):
    self.driver = webdriver.Firefox()

Zauważmy, że zamykamy przeglądarkę po każdym teście – czyli drugi test zakończy się błędem gdyz przeglądarka nie będzie uruchomiona. Czas skorzystać z metody która wykona się po wszystkich testach tearDownClass – dopiero wtedy nastapi zamknięcie przeglądarki

# def tearDown(self):
#     self.driver.close()

@classmethod
def tearDownClass(self):
    self.driver.close()

Metoda tearDown nie jest nam na razie potrzebna . Gdy wytniem z niej wiersz z zamknieciem drivera zgłaszała by błąd. Można ją zakomentować jak w przykładzie powyżej lub  tymczasowo zaślepić słowem pass albo usunąć:

def tearDown(self):
    pass

Teraz testy uruchamiają się na jednej instancji przeglądarki co wygląda jak prawdziwa akcja użytkownika.
Warto porównać czas wykonania dla testów w jednej i wielu instancjach przeglądarki:

Osobne przeglądarki: olx_main_tests.OlxMainTests 20.32 s
Jedna przeglądarka: olx_main_tests.OlxMainTests 6.748 s

Podsumowując:

Umiemy teraz napisać wiele testów sprawdzających tytuł strony
Testy mogą uruchomić się na jednej instancji przeglądarki
W testach są assercje co oznacza, że test automatycznie zakończy się niepowodzeniem gdy sprawdzany warunek okaże się błędny

Na koniec jeszcze wklejam cały kod z dzisiejszego posta

# -*- coding: utf-8 -*-
import unittest
from selenium import webdriver

class OlxMainTests(unittest.TestCase):
    @classmethod
    def setUpClass(self):
        self.driver = webdriver.Firefox()

    def setUp(self):
        self.EXPECTED_MAIN_TITLE = u'Ogłoszenia - Sprzedam, kupię na OLX.pl'

    def test_main_page(self):
        driver = self.driver
        driver.get('http://olx.pl')
        title = driver.title
        print(title)
        assert title == self.EXPECTED_MAIN_TITLE

    def test_oferty_page(self):
        driver = self.driver
        driver.get('http://olx.pl/oferty/')
        title = driver.title
        print(title)
        assert title == self.EXPECTED_MAIN_TITLE

    def test_zasady_page(self):
        driver = self.driver
        driver.get('http://olx.pl/zasady/')
        title = driver.title
        print(title)
        assert title == 'Regulamin OLX.pl'

    def tearDown(self):
        pass

    @classmethod
    def tearDownClass(self):
        self.driver.close()

Testy automatyczne Selenium cz2 – pierwsze kroki w pythonie.

AKTUALIZACJA

Najnowszą wersję tego wpisu w formie profesjonalnego (i na obecną chwilę darmowego) kursu znajdziesz na moim autorskim portalu https://jaktestowac.pl/course/pt1-mk1-podstawy-testow-automatycznych-w-selenium-i-python/.
Pozdrawiam Przemek

 

 

W tym poście opiszę jak rozpocząć przygodę z automatyzacją, która wiąże się z programowaniem. Od podstaw napiszę co trzeba zrobić aby stworzyć w pełni działający test automatyczny.

Przygotowanie środowiska

Testową aplikacja będzie olx.pl a wszystkie działania odbywaja się na maszynie z systemem Windows 7 z zainstalowaną przeglądarką Firefox
Zacznę od zainstalowania pythona na maszynie w wersji 2 linkDo pisania testów użyję IDE pycharm w darmowej wersji Community – jest to w pełni dojrzałe IDE i oferuje mnóstwo ciekawych funkcji link
UWAGA: Dokonaj update Fireoxa do najnowszej wersji

Utworzenie projektu

W PyCharmie tworzę nowy projekt – nazwę go olx_tests
Dodaję nowy plik (prawy klawisz myszki na folderze olx_test w widoku Projects) main_page_tests
2015-05-02_192101
Ustawiam pokazywanie numeru lini przy wierszach http://stackoverflow.com/a/8908562

UWAGA: Jeśli już wcześniej posiadałeś zainstalowanego pythona np. w wersji 3 to zainstaluj wesję 2 i ustaw ją dla naszego projektu:
przejdź w pycharmie File->Settings->Project:olx_tests (kliknij trójkąt z lewej)->Project Interpreter. Z listy wybierz odpowiedni interpreter lub klikając w trybik wskarz miejsce instalacji pliku python.exe ze ścieżki która domyślnie wygląda tak  C:\Python27\python.exe

Importowanie bibliotek

Biblioteki to takie gotowy kawałki kodu, dzięki którym nie trzeba wszystkiego pisać na nowo a wystarczy skorzystac z istnięjących roziwązań. Tutaj będę korzystał z biblioteki WebDriver o której funkcje opisane są tutaj

Czas jej użyć:

from selenium import webdriver

czyli z bilioteki selenium importujemy klasę webdriver.
Podkreślone na czerwono obie nazwy sugerują, że nasze IDE nie posiada zaimportowanych takich bibliotek.
PyCharm oferuje automatyczne importy więc klikam na nazwę selenium i wciskam kombinację klawiszy odpowiedzialną za podpowiedzi akcji naprawczych ALT + ENTER (powinna pojawić się także czerwona żarówka która można kliknąć i uzyskamy ten sam efekt).
Wybieram pierwszą opcję – install package selenium.
Podkreślenie powinno zniknąć co oznacza powodznie akcji.

UWAGA: Jeśli już wcześniej miałeś zainstalowaną bibliotekę selenium mozliwe, że potrzebny będzie Ci update: przejdź w pycharmie File->Settings->Project:olx_tests (kliknij trójkąt z lewej)->Project Interpreter. Odnajdź bibliotekę (Package) selenium a następnie upewnij się czy wartości w Version i Latest są identyczne. Jeśli nie to kliknij linie z selenium i naciśnij niebieską strzałkę skierowaną w górę z prawej strony. Następnie OK i juz masz zaktualizowaną bibliotekę.

Pierwszy kod

Czas skorzystać z webdriver: wpisuję więc kolejną linię
(warto zrobić jedeno linijkową przerwę pomiędzy deklaracjami importów a właściwym kodem – są to zalecenia formatowania języka python)

driver = webdriver.Firefox()

przypisuję tu do zmiennej driver obiekt który zawiera w sobie instancję przegladarki Firefox.

Uruchamianie kodu

Czas sprawdzić napisany kod – z górnego menu wybieram Run->Run..->main_page_test
Na dole pojawi się okno z informacjami na temat uruchomionego pliku i powinna zostać automatycznie uruchomiona instancja przeglądarki Firefox.
Zamykam okno Firefoxa co kończy test.

Sterowanie przeglądarką

Zmienna dirver jest jej reprezentacją więc można wywołać na niej różne funkcje – na przykład przejście do danego adresu:

driver.get('http://olx.pl')

Ostatnia konfiguracja uruchumieniowa została zapamiętana więc test można uruchomić  z kombinacji SHIFT + F10 lub kliknąć zieloną strarzałkę w prawym górnym rogu.

Tym razem przeglądarka powinna wyświetlić testowaną stronę.
W następnym kroku pobieram tytuł strony i zapisuję go do zmiennej title.
Kolejny wiersz to wypisanie zawartości zmiennej na konsole.

title = driver.title
print(title)

Po uruchomeinu testu uzyskałem taki rezultat
2015-05-02_215302UWAGA: text tytułu może ulec w każdej chwili zmianie więc zrwróć uwagę na wynik w konsoli i uaktualnij o nową wartość poniżej zaprezentowane przykłady.

Warunek pozytywnego zakończenia testu

Teraz dodam asercję czyli funkcję która porównuje dwie zmienne i w zależnie od rezultatu kończy się sukcesem bądź niepowodzeniem:

assert title == u'Ogłoszenia - Sprzedam, kupię na OLX.pl (dawniej Tablica.pl)'

UWAGA:  W łańcuchu znakowym znajdują się polskie znaki dlatego w powyższym kodzie umieściłem przed apostrofem znak u. Kolejnym krokiem jest dodanie kodu na samej górze pliku:

# -*- coding: utf-8 -*-

Wracamy do kodu z aserciją. Zauważmy, że zastosowałem tutaj  == ponieważ pojedynczy znak = słóży do przypisywania wartości do zmiennej,  w tym przypadku potrzebujemy porównania wartości.
(czyli x=5 oznacza, że x zwraca 5 a x==5 sprawdza czy x zawiera 5 i zwraca True albo False)
Uruchamiam ponownie test i nic się nie zmienia – ponieważ test pozytywnie się skończył.
Zróbmy jednak eksperyment:
Kopiuję linę  nr 5, komentuję ją za pomocą znaku # (dzięki czemu nie będzie wykonywana) a w kopii zmieniam adres na ebay.com czyli:

#driver.get('http://olx.pl')
driver.get('http://ebay.com')

Uruchamiam test i na konsoli otrzymuję:

Traceback (most recent call last):
 File "C:/tut/olx_tests/main_page_tests.py", line 9, in <module>
 assert title == u'Ogłoszenia - Sprzedam, kupię na OLX.pl (dawniej Tablica.pl)'
AssertionError
Electronics, Cars, Fashion, Collectibles, Coupons and More | eBay

Process finished with exit code 1

Widać, że tytuły który oczekiwaliśmy nie zgadza się z otrzymanym. Oraz mamy exit code 1 co oznacza, że pojawiły się problemy.

Wracam do poprawnej wersji driver.get (czyli odkomentowuję linię 5 i usuwam linię 6)
Aby ułatwić sobie sprawę dodaję automatyczne zamykanie przeglądarki – czyli wpisuję na końcu linię:

driver.close()

Podsumowanie i cały kod

I tym samym mam bardzo podstawowy test sprawdzający czy pod danym adresem znajduje się strona o określonym tytule.

Cały kodzik:

# -*- coding: utf-8 -*-
from selenium import webdriver

driver = webdriver.Firefox()
driver.get('http://olx.pl')
title = driver.title 
print(title)
assert title == u'Ogłoszenia - Sprzedam, kupię na OLX.pl (dawniej Tablica.pl)'
driver.close()

W nastepnym poście opiszę w jaki sposób grupować wiele testów, wyciągać z nich powtarzające się informację oraz jak to wszystko uruchomić w PyCharm http://przemek.yum.pl/testu-automatyczne-selenium-cz3-zestawy-testow/

Testy automatyczne Selenium cz1 – Selenium IDE

AKTUALIZACJA

Najnowszą wersję tego wpisu w formie profesjonalnego (i na obecną chwilę darmowego) kursu znajdziesz na moim autorskim portalu https://jaktestowac.pl/course/pt1-mk1-podstawy-testow-automatycznych-w-selenium-i-python/. Z samego Selenium IDE zrezygnowałem gdyż jest zbyt trudne do używania i w podobnym czasie zrobisz takie testy w profesjonalnym zestawie narzędzi (za darmo 🙂 )
Pozdrawiam Przemek

——————————————————————————————————————

Postanowiłem zrobić mały kursik, w którym od podstaw przedstawię proces tworzenia testów automatycznych. Skupię się w nim na testach GUI (warstwy prezentacji) aplikacji webowych czyli takich które mają za zadanie wiernie odwzorować zachowanie użytkownika na danej stronie.

Część 1 –  coś prostego i niezwykle szybkiego Selenium IDE
Do zastosowania w raczej prostych aplikacjach z niewielką ilościa podstron, w końcowej fazie rozwoju aplikacji – gdy zmiany na GUI nie są zbyt poważne a potrzeba zapewnienia o poprawnie działających komponentach.

  1. Zainstaluj przeglądarkę Firefox (albo uaktualnij do najnowszej wersji) – będę korzystał  i polecam wersję angielskojęzyczną
  2. Zainstaluj plugin Selenium:
    ja zrobiłem to manualnie:
    – pobrałem z oficjalnej strony Selenium http://release.seleniumhq.org/selenium-ide/2.9.0/selenium-ide-2.9.0.xpi
    – w FF w sekcji Menu/Add-ons (lub przez linka about:addons) klknąłem ikonkę trybika
    – skorzystałem z opcji

    Install Add-on From File...

    – zaakceptowałem i restart
    – w menu addons/Extensions powinny być widoczne zainstalowane rozszerzenia

  3. Zainstalowana wtyczka selenium objawia się ikonką  obok ikony menu FF
  4. Otwieram http://www.lolcats.com i klikam ikonkę wtyczki selenium co powoduje otwarcie nowego okna przeglądarki z programem selenium ide:
    2015-03-28_145952
  5. Nagrywam test (otwarcie wtyczki ustawia ją w stan automatycznego nagrywania):
    Przechodzę do strony testowej i odświeżam ją (F5), następnie do Galllery i klikam na baner LOLCATS.COM
    Wracam do wtyczki i zakańczam nagrywanie czerwonym przyciskiem record
  6. Mamy pierwszy test – powinien wyglądac tak:
    2015-03-28_151030Teraz odpalam test kozystając z zielonej ikonki ze strzałką i trzema prostokątami.
    Testy są ustawione na maksymalną szybkość i ze względu na jakiś tajemniczy bug potrafią się wysypać na ostatnim kroku:
    2015-03-28_151602Zmiejszenie prędkości powinno coś poprawić jednak wtyczka potrafi czasem się zawiesić i trzeba się z tym liczyć. Dobry wynik:
    2015-03-28_151701
  7. Taki test można zachować i odtwarzać ponownie.
    Można się pokusić o małą edycję:
    Kopiuję i wklejam krok z link=Gallery
    Klikam na zduplikowany krok
    Zmieniam w oknie Target z Gallery na Submit
    Uruchamiam test i widzę dodaną podstronę.
    Można również dograć kolejne kroki

W Selenium IDE oferuje o wiele więcej:
– grupowanie i zachowywanie przypadków testowych
– task scheduler pozwoli  na zaprogramowanie cykli wykonywania testów
– testy mozna wyeksportować do jednego z wielu wspieranych języków programowania
– testy można edytowac poprzez sekcję Source, zmieniać sposób w jaki elementy są odnajdywane na stronie
– jest wiele pluginów które rozszerzają funkcje  IDE można je znaleźć tu:
http://www.seleniumhq.org/download/#side_plugins

Wyeksportowanie skryptu do pythona (webdriver) dało prawie działające testy:
Trzeba było zaimportować bibliotekę selenium oraz zmienić usunąć końcowy slash z adresu – generalnie po tym zabiegu zaczeły działać.

Plugin Selenium IDE może wystarczyć do prostych testów jednak nie są one zbyt elastyczne , jak i stabilność wtyczki pozostawia wiele do życzenia. Aby uniknąć tych kłopotów warto skorzystać z bardziej zaawansowanej metody testów z użyciem Web Drivera – http://przemek.yum.pl/testy-automatyczne-selenium-cz2-pierwsze-kroki-w-pythonie/.

 

Słownik pod ręką – czyli tłumaczenie bez myszkowania

trans

Przepis na minimalistyczny słownik:
1. Klawisze skrótu do słownika
Pierszą fazą jest przeznaczenie osobnej przeglądarki na słownik dzięki temu można przypisać ją do skrótu klawiszowego i miec pewność, że zawsze ujżę słownik gdy ją wywołam. Na Windows wystarczy przypiąć przeglądarkę na pierwszej pozycji na pasku dostępu i za pomocą kombinacji klawiszy WIN+1 odwołać się do programu.  Ponowne użycie spowoduje powrót do poprzedniego okna. Aby przypisać inny skrót można posłużyć się programem AutoHotkey.  Trochę więcej zabawy było na LinuxMintale wiem z autopsji, że się da:)

2. Konfiguracja przeglądarki

Generalnie podobny efekt jest do uzyskania w każdej przeglądarce – ja proponuję modyfikację Chrome:
Zakładamy nowy profil w Chrome  https://support.google.com/chrome/answer/2364824?hl=pl
Wrzucamy wtyczkę:

https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=pl

Konfigurujemy wtyczkę:
Klik: ikone Tapermonkey
Klik: Dodaj nowy skrypt
Wklejamy (nadpisujemy wygenerowany kodzik)

// ==UserScript==
 // @name trans
 // @namespace http://your.homepage/
 // @version 0.1
 // @description enter something useful
 // @author You
 // @match https://translate.google.pl/
 // @require http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js
 // @grant none
 // ==/UserScript==</code>
$('#gb').remove()
 $('#gt-ft').remove()
 $('#gt-tl-gms').remove()
 $('#gt-lang-submit').remove()
 $('#gt-appbar').remove()
 $('#clear').remove()
 $('#gt-ft-res').remove()
 $('#gba').remove()
 $('#gt-swap').prependTo('#gt-src-tools');
 $('#gt-community-promo').remove()
 $('#gt-src-roman').remove()
 $('#gt-speech').remove()
 $('#gt-res-select').remove()
 $('#gt-pb-star').remove()
 $('#select_document').remove()
 document.getElementById('gt-text-top').style.paddingBottom = '0px'

Klik: save
W opcjach skrótu na pasku windows:
nowy_chrome
Przypinamy do paska, a potem wchodzimy w Properties
Ja mam taki target:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 2"

Dodaję:

 --kiosk --app="https://translate.google.pl/"

Czyli razem mam:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 2" --kiosk --app="https://translate.google.pl/"

Save

3. Odpalam ze skrótu i mam piękny słownik
Wystarczy go wypozycjonować i to przy każdym ponownym otwarciu będzie pojawiać się z określoną wilkością i pozyją
Przypinamy słownik (ja daję go na moje ulubione miejsce czyli pierwsze na pasku windows)
Co można zauważyć – mamy dwie ikony – przeglądarki która odpaliła słownik i słownik.
Zamień Target  pomiędzy tymi dwoma skrótami:

1. Po edycji przeglądarka główna ma miec skrót:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 2"

2. A słownik:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 2" --kiosk --app="https://translate.google.pl/"

(jak słownik jest aktywny to jest to ikona translate a jak wyłączony to zwykła ikona google) służy on po to aby słownik pojawiał się na właściwym miejscu ( gdy chcemy korzystac ze skrótu win+1)

Dla estetów do srótu desktopowego można dać ikonkę z

http://www.iconarchive.com/show/google-play-icons-by-marcus-roberto/Google-Translate-icon.html

4. Skróty jakich używam
Win+1  przejście/wyjście z translate
Tab+Enter okno puste = zmień język, okno z treścią = kasuj
LAlt+strzałka prawo/lewo nawigowanie po histrii
Tylko dla Opery:
Ctrl+n nowa karta – np dla http://www.diki.pl/
Tab+Ctrl przemieszczanie się między kartami
Ctrl+w zamknij tab

Teraz wystarczy powielić ten patern na wszystkich komputerach na których pracujemy i TADAAA uzależnienie gotowe 🙂

Efekt – dwa razy mniejsze dedykowane okno + tylko to czego potrzebuję + obsługa z klawiatury.
final

PS. Czasem zdarza się, że Google aktualizuje Tłumacza i trzeba zrobić również aktualizację skryptu… nic za darmo 😀

5. Gdy nienawidzimy gugla to można skorzystac ze starej Opery – efekt też jest ciekawy:

5.1 Pozbycie się niepotrzebnych kontrolek

Praktycznie każda przeglądarka oferuje wtyczkę która uruchomi skrypt pozwalający na wyczyszczenie niepotrzebnych elementów z używanej strony. W Operze12 użyłem rozszerzenia Scripter https://addons.opera.com/pl/extensions/details/scripter-script-includer
Po przejściu na stronę google translate do Scriptera ustawiłem opcję onready w Script execution order oraz dodałem prosty skrypcik usuwający/ukrywający dane elementy oraz przestawiający przycisk do zmiany języka tak aby można było do niego dostać się natychmiastowo klikając Tab

function loadScript(url, callback)
{
    // adding the script tag to the head as suggested before
   var head = document.getElementsByTagName('head')[0];
   var script = document.createElement('script');
   script.type = 'text/javascript';
   script.src = url;

   // then bind the event to the callback function 
   // there are several events for cross browser compatibility
   script.onreadystatechange = callback;
   script.onload = callback;

   // fire the loading
   head.appendChild(script);
}

loadScript("http://code.jquery.com/jquery-1.8.3.min.js", null)
$('#gb').remove()
$('#gt-ft').remove()
$('#gt-tl-gms').hide()
$('#gt-lang-submit').hide()
$('#gt-appbar').hide()
$('#clear').hide()
$('#gt-ft-res').hide()
$('#gba').hide()
$('#gt-swap').prependTo('#gt-src-tools');
document.getElementById('gt-text-top').style.paddingBottom = '0px'

5.2 Zagospodarowanie przestrzenne przeglądarki

Mój wybór padł na Operę v12 (wersja przed WebKitowa) gdyż pozwala na świetne modyfikacje okna. Usunąłem wszystkie bary i taby (prawy przycisk myszki na dowolnym barze -> Customise->Appearance… -> Toolbars) oraz zmiejszyłem widok o 10% (ctrl-). Po takim zabiegu do opcji Opery można się dostać poprzez malutki przycisk znajdujący się na środku lewej ramki okna
Okno pomniejszyłem maksymalnie tak aby nie generowało scroll barów oraz umieściłem w wygodnym miejscu na pulpicie.
transBlog3

Skrypt windows do parsowania xml umieszczonego w logu

Czasem trzeba odowiedzić loga – a tu zonk, wiadomość loggera zlepiona z xmlowym outputem:

2014-01-02 13:52:01.3850|TRACE|SuperService|Method GetStock ended with result: <Body xmlns:m="http://www.example.org/stock"><m:GetStockPrice><m:StockName>IBM</m:StockName></m:GetStockPrice></Body>

No i miliony takich linni kiedy mnie interesuje tylko ta najświeższa 🙂
Zacznijmy od pokazanej linijki – ląduje ona w pliku input.txt (jak? – o tym później) i zostanie przetworzony przez skrypt transform.bat

REM http://ss64.com/nt/for_f.html

@echo on
set file=input.txt
set out=output.xml
for /f "tokens=1,* delims=<" %%a in (%file%) do (
echo ^<DETAILS d^=^"%%a^"^>^<%%b^</DETAILS^>>%out%
)
pause

Krótki komentarz do linni
1 Tak się robi komentarze – w tym znajduje się link do fajnego omówienia tematu dzielenia tekstu w batch
3  Echo włączone – czyli widać jak nasz skrypt się wykonuje na konsoli – wystarczy zmienić parametr na off aby skrypt nie pokazywał okna
4 i 5 Ustawienie plików wejścia i wyjścia
6 Iteracja po liniach – token wydziela składniki z danej lini uzyskane za pomocą znaku rozdzielającego delims, w tym przypadku do 1 pobieram wszystko co znajduje się przed rozpoczęciem  znaku rozdzielającego – czyli aż do oraz resztę *, pierwsza wartość ląduje w zmiennej %%a  a pozostałe domyślnie w kolejnych %%b itd. do rozpoczyna sie ciało pętli
7 Do pliku output.xml zapisuję pierwszy wydobyty nie xmlowy tekst, który opakowuje  w tag – może on mieć dowolną nazwę, ja przyjąłem DETAILS oraz dodaję atrybut d który zawierać będzie wartość czyli pierwszy fragment tekstu. Wszystkie znaki specjalne które chcę zapisać do pliku escape’uje poprzez użycie daszka ^, oraz dokładam zmienną reprezentującą pierwszę linie %%a – powstaje coś takiego ^<DETAILS d^=^”%%a^”^>
Jako, że użyłem znaku < jako rozdzielacza trzeba go dodać bo jest on usuwany no i skleić z resztą lini z loga ^<%%b
Na koniec wystarczy dodać taga zamykającego ^</DETAILS^> i wszystko przekierować do pliku wynikowego >%out%
8 Zamykam petlę
9 I rozkazuję czekac skrypciochowi na moją reakcję 🙂

<DETAILS d="2014-01-02 13:52:01.3850|TRACE|SuperService|Method GetStock ended with result: "><soap:Body xmlns:m="http://www.example.org/stock"><m:GetStockPrice><m:StockName>IBM</m:StockName></m:GetStockPrice></soap:Body></DETAILS>

Jest nieźle – przy użyciu Notepad++ z zainstalowanym pluginem XML Tools wystarczy użyć opcji Pretty Print (ctrl+shift+alt+b)  i można podziwiać prawidłowo wyświetlonego XML

Ale to za mało czas na stworzenie czegoś w powershell

#last item from file
(Get-Content logfile.txt)[-2..-1]| Out-File -Encoding UTF8 input.txt
#adding xml marks to file
transform.bat
#formatting xml
[Reflection.Assembly]::LoadWithPartialName("System.Xml.Linq")
[System.Xml.Linq.XDocument]::Load("output.xml").Save("output_pretty.xml")
Get-Content output_pretty.xml
pause

Opis linii:
1 Komentarz
2 Wyjącie ostatniej lini z pliku (Get-Content logfile.txt)[-1] więcej możecie poczytać tu: http://technet.microsoft.com/en-us/library/ee692806.aspx
Następnie trzeba zapisać ze zmienionym kodowaniem bo domyślne USC-2 Little Endian nie za bardzo podchodzi skryptowi batch 🙂
4 Mając przygotowany plik z ostatnią linią można odpalić skrypt dodający tagi
6 Korzystanie z .NETowych bibliotek – dodaje Linq
Niby to jest już nieaktualna forma ale nie ma godnego zastępnika http://stackoverflow.com/questions/12923074/how-to-load-assemblies-in-powershell
7 Tu następuje proces transformacji jednolinijkowego xml do pliku
8 Zawartość ląduje na konsoli 

TADAAA – to już jest czytelne
powershell

Oczywiście przedstawiony case jest dość specyficzny – ale stanowi świetną bazę dla dalszych transformacji i eksperymentów.

Testy SOAP serwisu z logowaniem domenowym Windows

Mając zainstalowany SaoapUI próbowałem wygenerować interfejsy z pliku WSDL (Web Services Description Language) testowanego serwisu.  Potrzebne do tego było logowanie domenowe Windows.

SoapUI ładnie poprosił o podanie passów w okienku NT Authentication i potem jeszcze ładniej się zawiesił.

blog2

 

Szybkie ubicie procesu i chwila na stack’u przyniosły rozwiązanie:

  1. Potrzebny jest BurpSuite – wystarczy wersja free v1.5
  2. W zakładce Proxy > Intercept ustawiam Intercept is off
  3. W zakładce Proxy > Options dodaje w Proxy Listeners nowe proxy z portem 8081
  4. W zakładce Options > Connections w Platform Authentication
    – zaznaczam Do platform authentication
    – dodaje adres do zasobu w sieci lokalnej wystawionego na konkretnym procie
    blog4
    -zaznaczam Prompt for credentials on platform authentication failure
  5. Wracam do zakładki Proxy i zaznaczam Running w dodanym proxy
    Przełączam się na zakładkę Proxy > History na której będzie prezentowany log z działania proxy

Następnie przełączam się na SoapUI i w File > Preferences > Proxy Setting dodaje:
Host: localhost
Port: 8081
Enable Proxy:  zaznaczam enable using proxy

Następnie ponownie dodaje adres do WSDL i TADAAAAA! Lista metod powinna zostać pobrana a w Burp Suite można podziwiać logi z ruchu przez proxy 🙂

btool

Heroku – jak wystrzelić javową apkę w chmurę

Znowu chmura i java 😀

Standardowo trzeba założyć konto, tym razem na heroku.com. Można mieć do 5 darmowych apek a potem trzeba dać się zweryfikować przez podanie detali karty kredytowej – co się wtedy dzieje – nie wiem – ale na pewno jest w regulaminie zakaz tworzenia zsynchronizowanego tworu łączącego darmowe instancje w jedną zmutowaną apke 😀

Potem trzeba zainstalować konsolowego toola na kompie https://toolbelt.heroku.com/

Dla leniwych jest mega prosty projekt z prymitywnym gui którego bebechy można wrzucić do folderu z apką heroku https://github.com/AdupTeam/cloudcalc i spokojnie można przejść do części o push’owaniu 🙂

Tworzę apkę na heroku

$ heroku  apps:create hello-world
 !    Name is already taken

UPS! nazwa musi być unikalna – apka będzie widoczna pod domeną: mojanazwa.herokuapp.com

$ heroku  apps:create chmura
Creating chmura... done, stack is cedar
http://chmura.herokuapp.com/ | git@heroku.com:chmura.git

W odpowiedzi jest adres pod jakim znajdzie się apka i link do repo
Klonowanie pustego repo apki

$ git clone git@heroku.com:chmura.git
Cloning into 'chmura'...
warning: You appear to have cloned an empty repository.

UserX@X-PC ~/HerokuTest
$ cd chmura/

UserX@X-PC ~/HerokuTest/chmura (master)
$ ls -a
.  ..  .git

Domyślnie projekt powinien być w java 1.6 bo

       [ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project jbehave: Compilation failure
       [ERROR] Failure executing javac, but could not parse the error:
       [ERROR] javac: invalid target release: 1.7

Do pliku maven’owego pom.xml należy dodać plugin web runner

<build>
    ...
    <plugins>
        ...    
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals><goal>copy</goal></goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>com.github.jsimone</groupId>
                                <artifactId>webapp-runner</artifactId>
                                <version>7.0.40.0</version>
                                <destFileName>webapp-runner.jar</destFileName>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Tworzę plik Procfile (bez rozszerzenia, w najwyższej lokacji repo) z zawartością:

web:    java $JAVA_OPTS -jar target/dependency/webapp-runner.jar --port $PORT target/*.war

Czas kodzenia apki… Gdy mamy kod wystarczy zacommitować i ….

Czas pusznąć naszą ape na repo heroku oł je 😛

git push origin master

Powinno wyjść coś takiego

       [INFO] BUILD SUCCESS
       [INFO] ------------------------------------------------------------------------
       [INFO] Total time: 8.940s
       [INFO] Finished at: Sun Nov 03 15:41:57 UTC 2013
       [INFO] Final Memory: 20M/490M
       [INFO] ------------------------------------------------------------------------
-----> Discovering process types
       Procfile declares types -> web

-----> Compiled slug size: 61.4MB
-----> Launching... done, v8
       http://chmura.herokuapp.com deployed to Heroku

To git@heroku.com:chmura.git
   ae24ff2..f2e61e3  master -> master

A potem uruchomić dziada

UserX@X-PC ~/HerokuTest/chmura (master)
$ heroku ps:scale web=1
Scaling web dynos... done, now running 1

Gdyby działo się coś takiego

$ heroku ps:scale web=0
Scaling web dynos... failed
 ! Resource not found

prawdopodobnie jest coś nie tak z konfiguracją web-runner’a albo Procfile’a

Gdy już sie wszystko uda można klepnąć w konsolce

heroku run bash

No i sie porozglądać po DYNO czyli maszynce na jakiej siedzi apka

Podgląd tego co się dzieje z naszym heroku

heroku logs -t

A zapomniałbym –  można zobaczyć aplikację śmigającą w necie 🙂

heroku open

A potem usuwanko aby zrobić miejsce 🙂

UserX@X-PC ~/HerokuTest/cloudcalc (master)
$ heroku apps:create cloudcalc
 !    You've reached the limit of 5 apps for unverified accounts.
 !    Add a credit card to verify your account.

UserX@X-PC ~/HerokuTest/cloudcalc (master)
$ heroku apps:destroy chmura

 !    WARNING: Potentially Destructive Action
 !    This command will destroy chmura (including all add-ons).
 !    To proceed, type "chmura" or re-run this command with --confirm chmura

> chmura
Destroying chmura (including all add-ons)... done

Jeszcze można pobawić się tak:

Wersja pro – tworzymy heroku apke w isniejącym repo naszej apki na kompie

UserX@X-PC ~/HerokuTest/cloudcalc (master)
$ heroku apps:create cloudcalc
Creating cloudcalc... done, stack is cedar
http://cloudcalc.herokuapp.com/ | git@heroku.com:cloudcalc.git
Git remote heroku added

Czyli teraz można puszować do dwóch repo – nice 🙂

UserX@X-PC ~/HerokuTest/cloudcalc (master)
$ git remote -v
heroku  git@heroku.com:cloudcalc.git (fetch)
heroku  git@heroku.com:cloudcalc.git (push)
origin  https://github.com/AdupTeam/cloudcalc.git (fetch)
origin  https://github.com/AdupTeam/cloudcalc.git (push)

No to na co czekać 😀

UserX@X-PC ~/HerokuTest/cloudcalc (master)
$ git push heroku master
Counting objects: 26, done.
Delta compression using up to 3 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (26/26), 3.05 KiB, done.

git push każdy zna, heroku to nazwa repo, master to nasz branch który push’ujemy, opcjonalnie :master to zewnętrzny branch.

Warto pamiętać, że proces budowania jest odpalany tylko po push na branch master na repo heroku – inne gałęzie są ignorowane.

$ git push heroku mojbranch

Da

local mojbranch -> remote mojbranch

Przy polityce git, domyślnie tworzącego branch o nazwie tego z którego robimy push na repo zewnętrznym, powoduje brak budowania się apki. Wniosek – warto przyzwyczaić się do dodawania push heroku mojbranch:master gdy robimy push lokalnej gałęzi bo potem jest wielkie zdziwko czemu się nie buduje 😀

Idąc dalej można stworzyć dwie apki na heroku i podpiąc je pod repo oznaczając jako staging i production. Potem robić push do danego repo zewnętrznego – więcej o tym poczytasz na https://devcenter.heroku.com/articles/multiple-environments#advanced-linking-local-branches-to-remote-apps

Czasami się zdarza tak, że ostatni commit repo naszej apki, które chcemy push’nąć na świeżutkie repo heroku ma datę wcześniejszą niż commit inicjalizujący repo na heroku.
W logach pojawia się

pre-recive hook declined

, no i apka sie nie buduje. Rozwiązaniem jest zrobienie push z opcją

git push --force heroku mojbranch:master

co spowoduje nadpisanie naszym repo tego z heroku 🙂

Warto jeszcze dodać, że można podpiąć własną domenę pod apkę w chmurze.
W następnej części opisze proces dodania bazy do apki na heroku link TODO.

Do you realy like your wordpress theme – rapid customisation of default theme for noobies

You want to be sneaky – you want to be fast

I just wanted to have simple wordpress blog – ok… no probs

Switched newest Twenty Thirteen theme – looks fine – until I added my first post, and another…

This looks like some mess: full posts on front page – who the hell will scroll through long boring posts to find out what happening on my page. Ok, there is ‘Recent post’ widget but it only narrowing up site content even more. And that big space for title, it is really BIG, am I blind or what??? GRRRR that enough for me.

Googling for couple of minutes gives answers how to tame the beast 🙂
So here we go:

Post previews – like in search mode

go to Appearance, then Editor,  find content.php file in Templates in line 33 add places where preview mode should be available (add is_home() for homepage and so on)

<?php if ( is_search() || is_home() || is_category()) : 
// Only display Excerpts for Search - me - O really?>

And that silly comment : ‘Only display…’ – do something bad to it 🙂
Hit Update File and enjoy what other people call normal 😀

Time for style

Stay in the edit window and switch to Stylesheet style.css
Start messing around 🙂 There two ways
1. I don’t give a cat – replace original css with your custom
2. Pussy, pussy cat – install My Custom CSS plugin and add bits of edited code in it

Anyway, is good to have backup of original file. Another thing is to edit this file in some nice editor like Notepad++ or SublimeText3.

Let start – go to your min page in Chrome browser and hit F12 button

  1. Main banner – right click under the text on banner and choose option Inspect Element. Find line with  <a class expression
    baner edit
    on the right side you will find css style responsible for that guy in Style tab. Sometimes there is a lot of different styles but you can play with it values to find if change make you happy. Yes editing values in that styles works instantly and you can see how layout changes – find best values and then you can apply it to your code.  The same problem occurs with finding proper element on site – so little patience is needed.
    Ok – now use link on the right side of media=”all” starting with style.css it’s redirecting to part of css file responsible for everything in your life –  🙂 – for that banner
    baner edit css
    You can copy and paste this block of code in My Custom Css plugin  or navigate to the same line in original css style.
    Edit desired options – in my case max-width: 1200px; and min-height: 120px;
    good to add comments to css – must be closed in /*commnet */ so I paste

    /*Header width */ 
    .site-header .home-link {
    	color: #141412;
    	display: block;
    	margin: 0 auto;
    	max-width: 1200px;
    	min-height: 120px;
    	padding: 0 20px;
    	text-decoration: none;
    	width: 100%;
    }
  2. Save changes – and enjoy new  layout of header.
  3. To editing title – do the same procedure  to find code like
    <h1 class="site-title">Title of blog…</h1>

    Css style .site.title redirects to code

    .site-title {
    	font-size: 60px;
    	font-weight: bold;
    	line-height: 1;
    	margin: 0;
    	padding: 58px 0 10px;
    }

    Changing font-size: 40px; and  padding: 20px 0  10px; make my day 😀

  4. Next post width – found something like this:
    .sidebar .entry-header,
    .sidebar .entry-content,
    .sidebar .entry-summary,
    .sidebar .entry-meta {
    	max-width: 1040px;
    	padding: 0 376px 0 20px;
    }

    Changing max-width: 1300px; and padding: 0 210px 0 10px;

  5. I changed also padding between posts
    .hentry {
    	padding: 25px 0;
    }
  6.  Of course something was broken – sidebar overflow my text – so i applied some fixes, and additionally I added behaviour of  page when site width is below 1000px

Here is full code what can be inserted in My Custom Css and edited any time you like – or to be clear – don’t like something

/*Header width */ 
.site-header .home-link {
	color: #141412;
	display: block;
	margin: 0 auto;
	max-width: 1200px;
	min-height: 120px;
	padding: 0 20px;
	text-decoration: none;
	width: 100%;
}

/*Title */
.site-title {
	font-size: 40px;
	font-weight: bold;
	line-height: 1;
	margin: 0;
	padding: 20px 0 10px;
}

/*Main ite header*/
h1 {
	font-size: 30px;
	margin: 30px 0;
}

/*Post width*/

.sidebar .entry-header,
.sidebar .entry-content,
.sidebar .entry-summary,
.sidebar .entry-meta {
	max-width: 1300px;
	padding: 0 310px 0 10px;
}

/*To remove margin when smaller width*/
@media (max-width: 1000px) {

	.sidebar .entry-header,
	.sidebar .entry-content,
	.sidebar .entry-summary,
	.sidebar .entry-meta {
	max-width: 1200px;
	padding: 0 20px 0 20px;
	}
}

/*Pading between posts on main*/
.hentry {
	padding: 25px 0;
}

/*Sidebar*/
.site-main .sidebar-inner {
	margin: 0 auto;
	max-width: 1300px;
}

.site-main .widget-area {
		margin-right: 10px;
}

/*How wide the site is*/
.site {
	background-color: #fff;
	border-left: 1px solid #f2f2f2;
	border-right: 1px solid #f2f2f2;
	margin: 0 auto;
	max-width: 1350px;
	width: 100%;
}

 

Openshift pt3 Testuj w chmurze z Jenkins CI

build

W poprzednim tutorialu umieściłem apke na Jenkins’ie  aby mogła się automatycznie budować po zmianach w repo
http://przemek.yum.pl/openshift-2-buduj-w-chmurze-z-jenkins-ci/

Teraz czas na zabawę z setup’em Jenkins’a

  1. Zacznę od pluginów – zainstalujemy je klikając na Manage Jenkins  -> Manage Plugins  i już tutaj czeka na nas pierwsza pułapka
    W sekcji Available jest no właśnie – nic  – przechodzę do zakładki Advanced
    i tu klikam na  Check Updates. ten proces może potrwać dość długo – nawet kilka minut znane też były problemy z Chrome więc warto uzbroić się w cierpliwość.
    W najgorszym przypadku pluginy można dodać  z kompa.
  2. Dodaj plugina – oto opisy poszczególnych, które zainstaluje
    https://wiki.jenkins-ci.org/display/JENKINS/xUnit+Plugin
    https://wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin
    https://wiki.jenkins-ci.org/display/JENKINS/Dashboard+View
    https://wiki.jenkins-ci.org/display/JENKINS/Extra+Columns+Plugin
     i najważniejsze
    https://wiki.jenkins-ci.org/display/JENKINS/Green+Balls
  3. Będziemy jeszcze potrzebować wtyczki którą trzeba zainstalować ręcznie
    JBehave plugin  do pobrania tu https://nexus.codehaus.org/content/repositories/releases/org/jbehave/jbehave-jenkins-plugin/ i wybieram najnowszą oficjalną wersję, potem należy wybrać plik z rozszerzeniem hpi i mamy wtyczkę 🙂
    Gdyby jednak i pozostałe trzeba było ściągnąć – oto linki do nich
    http://updates.jenkins-ci.org/download/plugins/xunit/
    http://updates.jenkins-ci.org/download/plugins/greenballs/
    http://updates.jenkins-ci.org/download/plugins/cobertura/
    http://updates.jenkins-ci.org/download/plugins/dashboard-view/
    wystarczy klik w permalink i mamy pluginki
  4. Instalujemy je (zakładka Advaced) z kompa lub przez zakładke Available
    Po instalacji trzeba zrobić restart Jenkinsa – wbijam pod adres:
    https://jenkins-chmura.rhcloud.com/restart no i zatwierdam
  5. Naszym oczom ukazuje się greenball – koniec z dziadowskim niebieskim po udanym buildzie 🙂 Aale wato dodać więcej customu – klikam znak +  nad job’em i dodaje Dashboard. Wchodzę na niego i wybieram opcje po prawej stroni Edit View. Teraz można eksperymentować z jakimiś ciekawymi layoutami

Koniec zabawy  czas na konfiguracje job’a –
https://jenkins-chmura.rhcloud.com/job/calculator-build/configure

  1. Max # of builds to keep – jak już wspomniałem tak max 10
  2. Execute shell to jest ważne pole – znajduje się tu skrypt budowania apki
    Co jest ważne – gear build  trigger’uje

    mvn -e clean package -Popenshift -DskipTests'

    dlatego trzeba dodać fazę testów do naszego build’a – jest nawet na to przygotowane miejsce pod komentarzem 

    # Run tests here

    Więc dopisuję odpalanie testów i drobne info na konsole

    echo Starting tests
    mvn test

    Jeśli chodzi o nadpisanie zmiennej openshift’owej gear build  to niestety nie znalazłem rozwiązania i trzeba się z tym męczyć dodając osobno budowanie testów
    Dalej są dobrze udokumentowane stepy kopiowania zasobów pomiędzy pre i produkcyjnym środowiskiem oraz informacje o repo itd.

  3. Natepnie dodaję Post-build Action : Publish Cobertura Coverage Report
    ustawiam  pattern na: **/coverage.xml
    Wtyczka prezentuje raport porycia kodu przez testy
  4. Dodaję znów Post-build Action: Publish xUnit test result report
    Pod przyciskiem Add wybieram JBehave-3.x i ustawiam pattern an:
    **/jbehave/*.xml
    Aplikacja testowa którą sugeruje pobrać posiada testy BDD – jeśli w teojej aplikacji takich testów nie ma, można pominąć ten krok – ale zapraszam do tutorialu poświęconego dodawaniu testów BDD do projektu (TODO)
  5. Z pewnych ciekawych powodów wtyczka JBehave nie pozwala na odznaczenie opcji Post-build Action: Publish JUnit test result report z pattern’em **/*Test.xml. (Bo tak nazywam moje unit testy). Zaobserwowałem jednak pewną niestabilność i trzeba czasem pokombinować z dodaniem – usunięciem którejś ze wtyczek – widać kolejność ma znaczenie 🙂 Finalnie dane z testów powinny pochodzić z JBehave i z JUnit a przy padniętym buildzie po stronie unit testów tylko z JUnit. A co się stanie przy padniętych testach JBehave – trzeba sprawdzić 😀

Zapisuję tę ciężką pracę i odpalam build’a – zobaczmy co powie 😀

Już po dwóch build’ach powinien nam się ukazać taki oto widok:

build_coverage2

Czas coś w końcu dodać od siebie i zobaczyć jak maszina działa 😛

Wbrew boskim przykazaniom TDD zkodziłem sobie nową metodkę szybko i bezmyślnie

\src\main\java\com\rhcloud\pbtest\calculator\Calculator.java
  public void divide(int number1, int number2) {
        result = number1+number2;
    }

Co na to CI? Pokrycie kodziku spadło – w folderku Workscpace -> target/site/cobertura/index.html po kliknięciu w klasę znalazłem winnego

cobertura error

Dodaję więc klaskę testową już trochę bardziej przytomnie i push’uje na repo :

public class CalculatorDivideTest {
    private Calculator calc = new Calculator();

    @Test
    public  void shouldDivideNumberByAnotherNumber(){
        calc.divide(4,2);
        assertEquals("Divide unsuccessfull", 2, calc.getResult());
    }

}

Ola Boga cożech się stało – no tak… (smutek) Build czerwony…

No to szybko do wyników pod linkiem Test Result  a tam jak nic jest Test wywalony

calculator.CalculatorDivideTest.shouldDivideNumberByAnotherNumber

Error Message Divide unsuccessfull expected:<2> but was:<6>
Stacktrace 
java.lang.AssertionError: Divide unsuccessfull expected:<2> but was:<6>

Fiksuje ten niewybredny błąd w mojej metodzie i wszystko wraca do zieloności 🙂

Warto wiedzieć
  1. Logi na Jenkis można podglądnąć:
    a) Wchodząc w job’a i klikając na ikonkę Ball w Build History
    b) Wchodząc w konkretnego build’a w Build History  -> Console Output
    c) Dodając i konfigurując Extra Collumn plugin – najświeższe logi są dostępne już z job’a – efekt możecie podziwiać na obrazku na początku postu 🙂
  2. W Manage Jenkins -> Cnfigure System->Default view możemy ustawić naszeg custom’owego dashbord’a 🙂
  3. Nie trzeba wpadać na Jenkins’a aby szybko podglądnąc jaki był wynik build’a – w terminalu wystarczy wpisać i dostaniemy feedback – to jest generyczne dla każdej openshift’owej apki – czyli można też tak podglądnąć logi apki calculator
    rhc tail jenkins
    Nov 03, 2013 3:12:44 AM hudson.model.Run execute
    INFO: calculator-build #59 main build action completed: SUCCESS
  4. Pliki po zbudowaniu apki w job’ie na testowym workspace są automatycznie kasowane po 15 minutach bezczynności – jednak można to obejść
    po pierwsze wydłużając ten czas w ustawieniach Jenkinsa do 60min w Slave Idle Time to LiveMax Slave Idle Time to Live
    po drugie dodając nowego jenkins’owego job’a  (ustawienia konfiguracyjne trzeba skopiować z głównego job’a [bez git’a, shell’a i plugin’ów ]) i ustawiając cron’a w Build Triggers  na np  0,55 * * * *   czyli co 55min będzie wykonywał się pusty build więc pliczki nie powinny być kasowane

To by było na tyle odnośnie testów, Jenkins na Openshift. Z pewnością w innych postach będę wspominał o różnych sposobach testowania apki javowej – co z powodzeniem można zastosować w chmurze 🙂 ….

W kolejnym poście opiszę proces dodania bazki i phpMyAdmin do apki na Openshift link (TODO)