Testowanie aplikacji webowej, Spring, Mockito

0

Cześć,

w niedługim czasie mam pisać testy dla aplikacji. Mam kilka pytan:

Najpierw chce przetestwac DAO i menadzery do obslugi bazy:

  1. Tutaj nie musze uzywac Mockito, prawda ? (mam dostep do wszystkiego, moge np. sobie zapisywac jakies obiekty i asercja sprawdzic dla testu metody save)

  2. Sa jakies kompletne przyklady dobrych testow dla DAO i menadzerow zapisu w internecie ? (nie moge znalezc nic konkretnego)

Pozniej bede testowal gui, np. uruchamiam okno ktore generuje wyniki z bazy, odczytuje wyniki z okna i porownuje z wlasciwymi.

  1. Jak sie za to zabrac ?
  2. Czy tu przyda mi sie Mockito ? (mysle, ze tak, obsluge bazy bede mial juz na rzeczywistych przykladach z punktow powyzej przetestowana, to teraz sobie je zamockuje by przetestowac gui)
  3. Sa jakies kompletne przyklady dobrych testow dla GUI aplikacji webowej ?

z góry dzięki za wszystki wskazowki

2
  1. Wręc przeciwnie! Mocki nie są po to żeby ich używac "jak nie masz dostępu" tylko po to żeby dalo się to szybko i łatwo testować! To znaczy bez konieczności stawiania bazy danych i wypełniania jej danymi testowymi na przykład...
  2. Po prostu zrób 100 pokrycia i będzie ok :P
    To GUI jest webowe? Jesli tak to masz Selenium.
0

ok, zanim zaczne testowac gui to jeszcze minie troche czasu, skupie sie na razie na *DAO i menadzerach dostepu bazy.

nie bardzo rozumie zastosowanie tych mockow o ktorych piszesz.

mam klase dajmy na to FakturaDAO, ktora ma metode save.

Robie klase TestFakturaDAO, wstrzykuje Springiem FakturaDAO, tworze metode TestSave() zapisuje dwa elementy do bazy i sprawdzam asercja czy sa dwa elementy.

Jak tu uzyc Mockow ?
Jesli nie bede wstrzykiwal FakturaDAO, a zamista tego ja zmockuje, to jak to moge przetestowac ?

2

Ale co ty chcesz teraz przetestować? Metodę save? A co ona robi? Jeśli to jest metoda którą sam napisałeś to zwyczajnie: mockujesz wszystkie zalezności tej metody (wszystkie klasy i obiekty z których korzysta) i testujesz wszystkie ścieżki wywołania tej metody. Jeśli metoda korzysta z innych metod tej klasy to je też (!) mockujesz! Jeśli to nie jest metoda napisana przez ciebie, to jej nie testujesz bo nie ma sensu. Przykład:

//klasa nazywa się TestowanaKlasa
public boolean metoda(){
  if(warunek(){
    try{
      Obiekt x = new Obiekt();
      x.cośtam(); //może rzucić wyjątek
      return true;
    }catch(SomeException e){
      //cośtam
      return false;
    }
  }else{
    return false;
  }
}

I do tego mamy przykładowo taki test:

@Test
public void testMetoda(){
//mocki
TestowanaKlasa tk = createNicePartialMockForAllMethodsExcept(TestowanaKlasa.class,"metoda"); //mockujemy wszystko oprócz tej metody którą testujemy
Obiekt o = createNiceMock(Obiekt.class);

//zachowanie mocków
expect(tk.warunek()).andReturn(true).times(2).andReturn(false).once(); //wywołamy metodę 3 razy, dwa razy chcemy wejść do ifa, raz do else
expectNew(Obiekt.class).andReturn(o).twice(); //dwa razy będziemy tworzyć Obiekt w ifie
expect(o.cośtam()).andThrow(new SomeException()).once(); // za pierwszym razem rzucimy wyjątek
replayAll();

//wywołanie testów
boolean wynik1 = tk.metoda();
boolean wynik2 = tk.metoda();
boolean wynik3 = tk.metoda();

assertFalse(wynik1);
assertTrue(wynik2);
assertFalse(wynik3);

verifyAll();
}
0

tak sie teraz zastanawiam (o ile dobrze zrozumialem) jaki sens maja te wszystkie testy, przeciez to wszystko widac bez testowania. Te testy to taka troche sztuka dla sztuki :D

Czy dobrze rozumiem test metody save:

A - to moja klasa, B b ma referencje do klasy, ktorej nie pisalem (jakas tam biblioteczna zalozmy) :

A {
void save(int a) {
b.save(a);
}
}

pisze klase TestA, ktora mockuje klase B, okreslam na mocku, ze powinienem raz tylko wywolac jesgo wewnetrzne save.
Wywoluje save (rzeczywistej, nie mockowanej referencji do obiektu A w kalsie TestA) Jesli save z mocka wywolalo sie raz, to jest ok.

Jaki tego sens wszystkiego to nie rozmumiem :D

1

Ech. Sens jest taki że TERAZ ten kod wygląda tak. Ale za jakiś czas ty albo ktoś inny może potrzebować go zmienić. Takie już jest życie że jak piszesz kod to on zwykle jeszcze jakoś wygląda i "widać na oko" że jest ok. Ale kod bardzo szybko się psuje, bo co chwilę się do niego coś dopisuje. Testy jednostkowe są właśnie po to, żebyś mógł po dopisainu / modyfikacji kodu je uruchomić i zobaczyć czy czegoś nie zepsułeś.
Przykład z twoją metodą: wyobraźmy sobie że za jakiś czas okaże się ze jednak nie wszystkie inty powinny być zapisywane w bazie i musisz dorobić tam warunek który sprawdza jaką int ma wartość i w zalezności od tego wykonuje akcję. Załóżmy że formuła sprawdzająca czy int jest dobry czy nie jest dość skomplikowana. Dopisujesz ją i modyfikujesz test tak żeby działał z nią poprawnie.
Za tydzień twój kolega Franek majstrje coś przy ty kodzie, dodaje loggery etc i widzi że masz tam tą skomplikowaną formułę. Franek uważa że jest lepszy od ciebie i umie ją napisać krócej i łatwiej. Franek ją zmienia (oczywiście niepoprawnie) i gdyby nie to że test jednostkowy, to nikt by nie wiedział że coś się zepsuło.
Poza tym w przypadku twojego kodu, jeśli b.save() może rzucać wyjątek to code-coverage od razu powie ci ze tego nie przetestowałeś. Dzięki pisaniu testów mozesz łatwo sprawdzić czy kod działa tak jak ci się wydaje że działa. Czasem "na oko" tego nie widać jak masz kilka ifów, forów i try-catchów.

0

ok, no dzieki, teraz wiem jak sie za to zabrac :)

ostatnie pytanie: "Poza tym w przypadku twojego kodu, jeśli b.save() może rzucać wyjątek to code-coverage od razu powie ci ze tego nie przetestowałeś"

w jakim sensie: "code-coverage od razu powie ci ze", nie rozumie tego :) ?

W jaki sposob moge przetestowac, ze ta metoda z klasy b moze rzucic wyjatek, jak to uwzglednic w tescie ?

1

Jak puścisz sobie raport pokrycia kodu (np. za pomocą wtyczki do Eclipse Code-Cover) to taka wtyczka sprawdza czy wykonanie twojego testu spowodowało wywołanie wszystkich linii kodu testowanej metody. Jesli wiec w twojej metodzie jest catch() do którego w trakcie testu nie wchodziłeś to dostaniesz taka informację.
Pokazałem w kodzie wyżej jak rzucic mockiem wyjątek.

0
public boolean metoda(){
  if(warunek(){
    try{
      Obiekt x = new Obiekt();
      x.cośtam(); //może rzucić wyjątek
      return true;
    }catch(SomeException e){
      //cośtam
      return false;
    }
  }else{
    return false;
  }
}

jest srednio testowalny, poniewaz masz new Object(), i chcesz testowac metode w zaleznosci tego co sie stanie jak wywolasz x.cośtam - ale tej metody nie da sie mockowac. Tworzenie musialoby byc robione przez jakas zaleznosc, ktora da sie mockowac tak, aby zwracala mocka, ktory raz rzuca wyjatek, raz nie, itp.

0

Widze w sumie ze uzywasz PowerMocka, czyli da sie, ale nie lubie takiej magii, ta metoda ktora testujesz ma tyle podmienionego bytecodu w runtime ze nic z niej prawie nie zostaje. Da sie pisac kod ktory da sie testowac bez takich mykow. A proponenci DI od dawna trabia, ze new w kodzie jest beeeee.

1

@mućka jasne że tak, ale jak często piszesz w pracy własny kod, a jak często poprawiasz coś w już istinejacym, który o DI nigdy nie słyszał? ;)
A metoda którą tutaj przedstawiłem do testowania jest nietknięta. Cała reszta tej klasy jest podmieniona :) Taka przecież jest idea testowania jednostkowego, żeby testować mały fragment niezaleznie od reszty.

1

Tak, tutaj masz racje co do obcego kodu - niestety mam w pracy takiego mnostwo, mimo ze uzywaja Springa. Co do tej jednostki - nie zgodze sie ze jest nietknieta - przeciez samo new Object() jest tutaj podmienione na cos innego, naprawde nie wola new Object tylko PoweMock robi jakies cuda. Ale ok, fajnie ze tak sie da, musze sie przyjrzec PM nieco doglebniej ;d

1 użytkowników online, w tym zalogowanych: 0, gości: 1