Z´aklady programovan´ı 3 - Java
Unit testy Petr Krajˇca Katedra informatiky Univerzita Palack´ eho v Olomouci
26.,27. listopad, 2014
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
1 / 14
Testov´an´ı z´asadn´ı ˇc´ast v´yvojov´eho cyklu ˇcasto z mnoho d˚ uvod˚ u podceˇ novan´a protoˇze: nen´ı na to ˇcas ,,vˇzdyt’ mˇe to funguje, zkouˇsel jsem to” z´akazn´ık to stejnˇe nepozn´a, kdyˇz to trochu oˇsid´ıme testov´an´ı je nudn´e, ps´at k´ od je vˇetˇs´ı z´abava atd.
ˇrada pˇr´ıstup˚ u k testov´an´ı od modelu vodop´ad aˇz k testy ˇr´ızen´emu v´yvoji—TDD od ad hoc test˚ u k automatick´ym
pˇri volbˇe spr´avn´eho pˇr´ıstupu je postaˇcuj´ıc´ı/vhodn´e/nutn´e pouˇz´ıvat zdrav´y rozum
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
2 / 14
Druhy test˚ u ad hoc testov´an´ı unit (jednotkov´e) testy – testov´an´ı nejmenˇs´ıch ˇc´ast´ı k´odu integraˇcn´ı testy – testuje rozhran´ı mezi jednotliv´ymi ˇc´astmi syst´emu syst´emov´e testy – ovˇeˇruj´ı funkˇcnost syst´emu jako celku a dalˇs´ı – akceptaˇcn´ı, regresn´ı testy; alfa, beta testov´an´ı Omezen´ı nelze otestovat vˇse lze pouze dok´azat pˇr´ıtomnost chyby, ne spr´avnost programu probl´emy s testov´an´ım interaguj´ıc´ıch ˇc´ast´ı (UI, datab´aze, atd.)
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
3 / 14
Druhy test˚ u ad hoc testov´an´ı unit (jednotkov´e) testy – testov´an´ı nejmenˇs´ıch ˇc´ast´ı k´odu integraˇcn´ı testy – testuje rozhran´ı mezi jednotliv´ymi ˇc´astmi syst´emu syst´emov´e testy – ovˇeˇruj´ı funkˇcnost syst´emu jako celku a dalˇs´ı – akceptaˇcn´ı, regresn´ı testy; alfa, beta testov´an´ı Omezen´ı nelze otestovat vˇse lze pouze dok´azat pˇr´ıtomnost chyby, ne spr´avnost programu probl´emy s testov´an´ım interaguj´ıc´ıch ˇc´ast´ı (UI, datab´aze, atd.)
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
3 / 14
Ide´aln´ı test s nˇejakou formou testov´an´ı se setkal asi kaˇzd´y bylo to dobˇre proveden´e testov´an´ı? byl to produktivnˇe str´aven´y ˇcas? nemohl by to udˇelat nˇekdo jin´y? =⇒ automatick´e testov´an´ı Dobr´ y (automatick´ y) test rychle napsan´y =⇒ nechceme s nimi ztr´acet ˇcas srozumiteln´y =⇒ chceme test˚ um rozumˇet rychl´y =⇒ chceme dˇelat testy ˇcasto (kdykoliv je to potˇreba) Proˇ c (automaticky) testovat aplikace? ovˇeˇren´ı, ˇze vˇsechno dˇel´a, co m´a moˇznost zjistit, ˇze zmˇena v jedn´e ˇc´asti nerozbila jinou ˇc´ast pˇr´ıleˇzitost zmˇenit implementaci bez zmˇeny rozhran´ı (refactoring) forma dokumentace Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
4 / 14
Ide´aln´ı test s nˇejakou formou testov´an´ı se setkal asi kaˇzd´y bylo to dobˇre proveden´e testov´an´ı? byl to produktivnˇe str´aven´y ˇcas? nemohl by to udˇelat nˇekdo jin´y? =⇒ automatick´e testov´an´ı Dobr´ y (automatick´ y) test rychle napsan´y =⇒ nechceme s nimi ztr´acet ˇcas srozumiteln´y =⇒ chceme test˚ um rozumˇet rychl´y =⇒ chceme dˇelat testy ˇcasto (kdykoliv je to potˇreba) Proˇ c (automaticky) testovat aplikace? ovˇeˇren´ı, ˇze vˇsechno dˇel´a, co m´a moˇznost zjistit, ˇze zmˇena v jedn´e ˇc´asti nerozbila jinou ˇc´ast pˇr´ıleˇzitost zmˇenit implementaci bez zmˇeny rozhran´ı (refactoring) forma dokumentace Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
4 / 14
Ide´aln´ı test s nˇejakou formou testov´an´ı se setkal asi kaˇzd´y bylo to dobˇre proveden´e testov´an´ı? byl to produktivnˇe str´aven´y ˇcas? nemohl by to udˇelat nˇekdo jin´y? =⇒ automatick´e testov´an´ı Dobr´ y (automatick´ y) test rychle napsan´y =⇒ nechceme s nimi ztr´acet ˇcas srozumiteln´y =⇒ chceme test˚ um rozumˇet rychl´y =⇒ chceme dˇelat testy ˇcasto (kdykoliv je to potˇreba) Proˇ c (automaticky) testovat aplikace? ovˇeˇren´ı, ˇze vˇsechno dˇel´a, co m´a moˇznost zjistit, ˇze zmˇena v jedn´e ˇc´asti nerozbila jinou ˇc´ast pˇr´ıleˇzitost zmˇenit implementaci bez zmˇeny rozhran´ı (refactoring) forma dokumentace Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
4 / 14
Unit testy testuj´ı se nejmenˇs´ı ˇc´asti programu (obsahuj´ıc´ı nˇejakou logiku) nejˇcastˇeji jednotliv´e metody/funkce na z´akladˇe jejich specifikace oˇcek´av´ame urˇcite chov´an´ı (contract) napˇr. na z´akladˇe vstup˚ u oˇcek´av´ame specifikovan´y v´ystup/zmˇenu stavu objektu testy by mˇeli b´yt ,,hloup´e” a neobsahovat vlastn´ı ,,logiku” (r˚ uzn´e v´ypoˇcty, if, for, switch) =⇒ riziko vytvoˇren´ı ˇspatn´eho testu mˇely by b´yt testov´any i mezn´ı pˇr´ıpady
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
5 / 14
Frameworky psan´ı test˚ u by mˇelo b´yt co nejpohodlnˇejˇs´ı tˇr´ıdy obsahuj´ıc´ı metody prov´adˇej´ıc´ı jednotliv´e testy vyznaˇceny s pomoc´ı anotac´ı jestli je dan´y test splnˇen je d´ano pomoc´ı jednotliv´ych tvrzen´ı (assertions) assertEquals(expected, actual) assertTrue(condition) ...
pro zjednoduˇsen´ı se pouˇz´ıvaj´ı frameworky – JUnit, NUnit, atd. =⇒ moˇznost integrace v IDE
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
6 / 14
Pˇr´ıklad pouˇzit´ı (1/2) public class Counter { private int state = 0; public Counter() { super(); } public void add() { this.state++; } public int getValue() { return this.state; } } Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
7 / 14
Pˇr´ıklad pouˇzit´ı (2/2) import org.junit.Assert; import org.junit.Test; public class CounterTest { @Test public void basicTest1() { Counter c = new Counter(); c.add(); Assert.assertEquals(1, c.getValue()); } @Test public void basicTest2() { Counter c = new Counter(); c.add(); c.add(); Assert.assertEquals(2, c.getValue()); } Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
8 / 14
Moˇzn´e vylepˇsen´ı a u´skal´ı spoleˇcn´a inicializace: metody oznaˇcen´e @Before spoleˇcn´y ,,´ uklid”: metody oznaˇcen´e @After Co vˇsechno testovat? vˇsechny funkce maj´ıc´ı veˇrejn´e rozhran´ı (public metody) nem´a smysl testovat soukrom´e metody ALE! testy by mˇely proj´ıt vˇetˇsinu ˇr´adk˚ u k´ odu nem´a smysl testovat funkci primitivn´ıch getter˚ u/setter˚ u ALE! m´a smysl testovat d˚ usledky jejich zmˇeny Kdy ps´ at unit testy? pokud to jde, pˇred psan´ım k´ odu pokud to nejde, je dobr´e ovˇeˇrit, ˇze nov´y test funguje pˇri objeven´ı chyby a pˇred jej´ı opravou
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
9 / 14
Moˇzn´e vylepˇsen´ı a u´skal´ı spoleˇcn´a inicializace: metody oznaˇcen´e @Before spoleˇcn´y ,,´ uklid”: metody oznaˇcen´e @After Co vˇsechno testovat? vˇsechny funkce maj´ıc´ı veˇrejn´e rozhran´ı (public metody) nem´a smysl testovat soukrom´e metody ALE! testy by mˇely proj´ıt vˇetˇsinu ˇr´adk˚ u k´ odu nem´a smysl testovat funkci primitivn´ıch getter˚ u/setter˚ u ALE! m´a smysl testovat d˚ usledky jejich zmˇeny Kdy ps´ at unit testy? pokud to jde, pˇred psan´ım k´ odu pokud to nejde, je dobr´e ovˇeˇrit, ˇze nov´y test funguje pˇri objeven´ı chyby a pˇred jej´ı opravou
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
9 / 14
Moˇzn´e vylepˇsen´ı a u´skal´ı spoleˇcn´a inicializace: metody oznaˇcen´e @Before spoleˇcn´y ,,´ uklid”: metody oznaˇcen´e @After Co vˇsechno testovat? vˇsechny funkce maj´ıc´ı veˇrejn´e rozhran´ı (public metody) nem´a smysl testovat soukrom´e metody ALE! testy by mˇely proj´ıt vˇetˇsinu ˇr´adk˚ u k´ odu nem´a smysl testovat funkci primitivn´ıch getter˚ u/setter˚ u ALE! m´a smysl testovat d˚ usledky jejich zmˇeny Kdy ps´ at unit testy? pokud to jde, pˇred psan´ım k´ odu pokud to nejde, je dobr´e ovˇeˇrit, ˇze nov´y test funguje pˇri objeven´ı chyby a pˇred jej´ı opravou
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
9 / 14
Pˇreteˇcen´ı do integraˇcn´ıch test˚ u kaˇzd´y unit test by mˇel testovat jednu vˇec =⇒ probl´em tˇesnˇe propojen´ych komponent unit test by nemˇel interagovat s okol´ım (s´ıt’, souborov´y syst´em, datab´aze) =⇒ zpomalen´ı test˚ u, nutnost pˇripravit prostˇred´ı, nen´ı zaruˇcen´e, ˇze test uspˇeje, kdyˇz m´a vytvoˇren´ı maket objekt˚ u oddˇelen´ı integraˇcn´ıch test˚ u =⇒ moˇznost pouˇz´ıt stejn´e n´astroje jak pro unit testy
pokud je potˇreba sloˇzit´a inicializace =⇒ zˇrejmˇe ˇspatn´y unit test
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
10 / 14
Nevhodn´y test (1/2) Metoda tˇr´ıdy Board public List<Move> getAllLegalMoves(Piece p) { List<Move> result = LinkedList<Move>(); for (int i = 0; i < 8; i++) for (int j = 0; j < 8; j++) { Move m = new Move(p.getPosition(), new Position(i, j)); if (this.isLegalMove(m)) result.add(m); } return result; }
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
11 / 14
Nevhodn´y test (2/2) @Test public void testAllLegalMoves1() { Board b = createBoard(); Piece p = b.getPiece(...); List<Move> moves = b.getAllLegalMoves(p); for (Move m: moves) Assert.assertTrue(b.isLegalMove(m)); }
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
12 / 14
Testov´an´ı pr´ace se soubory (1/2) Jako integraˇ cn´ı test @Before public void setUp() throws IOException { Board b = createBoard(); b.saveBoard("/tmp/foo"); } @After public void tearDown() throws IOException { File f = new File("/tmp/foo"); f.delete(); } @Test public void loadTest1() { Board b = Board.loadBoard("/tmp/foo"); // ... } Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
13 / 14
Testov´an´ı pr´ace se soubory (2/2) Probl´ emy 1
magick´e hodnoty
2
testuj´ı se dvˇe r˚ uzn´e vˇeci: uloˇzen´ı i naˇcten´ı
3
z´apis na disk m˚ uˇze selhat (pr´ava, zaplnˇen´ı, atd.)
ˇ sen´ı Reˇ 1
pouˇzit´ı konstant
2
m´ısto uloˇzen´ı pomoc´ı saveBoard zapsat test pˇr´ımo
3
upravit ˇcten´ı, aby nepotˇrebovalo pˇr´ıstup na disk
public static Board load(InputStream stream) { ... } Board b1 = Board.load(new FileInputStream("/tmp/blah"); Board b2 = Board.load(new StringInputStream("
Petr Krajˇ ca (UP)
Unit testy
26.,27. listopad, 2014
14 / 14