Kapitola 1. Přednáška 7 - testování a ladění programů, junit, assert. Javové operátory, složitější výrazy. Obsah Ladění a testování programů .........................................................................................1 Ladění programů v Jávě .......................................................................................2 Ještě lepší...........................................................................................................2 Postup pří práci sassert....................................................................................2 Ukázka použití assert (1) ......................................................................................3 Ukázka použití assert (2) ......................................................................................4 Ukázka použití assert (3) ......................................................................................5 Ukázka použití assert (4) ......................................................................................5 Postup pří práci s JUni t......................................................................................5 Ukázka použití JUnit (1).......................................................................................6 Ukázka použití JUnit (2).......................................................................................7 Ukázka použití JUnit (3).......................................................................................7 Ukázka použití JUnit (4).......................................................................................8 Postup pří práci sjass ........................................................................................9 Odkazy ...........................................................................................................10 Operátory a výrazy, porovnávání objektů.......................................................................10 Aritmetické......................................................................................................11 Logické...........................................................................................................11 Relační (porovnávací) ........................................................................................11 Porovnávání objektů..........................................................................................12 Porovnávání objektů - příklad..............................................................................12 Metoda hashCode..............................................................................................13 Metoda hashCode - příklad .................................................................................13 Bitové.............................................................................................................14 Operátor podmíněného výrazu ? : ......................................................................14 Operátory typové konverze (pretypovaní) ..............................................................14 Operátor zřetězení + ..........................................................................................15 Priority operátorů a vytváření výrazů ....................................................................15 Ladění a testování programů • Ladění programů s debuggerem jdb • Nástroje ověřování podmínek za běhu - klíčové slovo assert 1 Přednáška 7 - testování a ladění programů, junit, assert. Javové operátory, složitější výra- • Nástroje testování jednotek (tříd, balíků) - junit • Pokročilé systémy dynamického ověřování podmínek - jass Ladění programů v Jávě Je mnoho způsobů... kontrolní tisky - System, err. println (...) • řádkovým debuggerem j db • integrovaným debuggerem v IDE • pomocí speciálních nástrojů na záznam běhu pg.: nejrůznější "loggery" - standardní poskytuje od JDK1.4 balík j ava. util. logging nebo alternativní a zdařilej ší 1 o g 4 j Jeste lepši... • je používat systémy pro běhovou kontrolu platnosti podmínek: • vstupní podmínka metody (zda je volána s přípustnými parametry) • výstupní podmínka metody (zda jsou dosažené výstupy správné) • a podmínka kdekoli j inde - např. invariant cyklu... • K tomuto slouží j ednak standardní klíčové slovo (od JDK1.4) assert booleovský výraz • testovací nástroje typu JUnit (a varianty - HttpUnit,...) - s metodami assertEquals () apod. • pokročilé nástroje na běhovou kontrolu platnosti invariantů, vstupních, výstupních a dalších podmínek - např. jass (Java with ASSertions), http://csd.informatik.uni-oldenburg.de/~jass/. • Ukázka testu jednotky:Test třídy ChovatelPsu [http://www.fi.muni.cz/~tomp/java/ucebnice/javasrc/svet/chovatelstvi/psi/ChovatelPsuTest.java] Postup při práci S assert Postup: 2 zy. 1. Napsat zdrojový program užívající klíčové slovo assert (pouze od verze Java2 vl.4 výše). Nepotřebujeme žádné speciální běhové knihovny, vseje součástí Javy; musíme ovšem mít překladové i běhové prostředí vl.4 a vyšší. 2. Přeložit jej s volbou -source 1. 4 3. Spustit jej s volbou-ea (-enableassertions). Aktivovat aserce lze i selektivně pro některé třídy (-ea název_třidy nebo -ea ná-zev_baliku. . . - tři tečky na konci!!!). 4. Dojde-li za běhu programu k porušení podmínky stanovené za assert, vznikne běhová chyba (AssertionError) a program skončí. Ukázka použití assert (1) Třída Zlomek používá assert k ověření, že zlomek není (chybou uživatele) vytvářen s nulovým jmenovatelem. Za assert uvedeme, co musí v daném místě za běhu programu platit. Obrázek 1.1. Třídy AssertDemo, Zlomek 3 Přednáška 7 - testování a ladění programů, junit, assert. Javové operátory, složitější výra- AssertDemo.java package tomp.učebnice.assertions; public class AssertDemo < public static uoid main(String[] args) { Zlomek x = neu Zlomek(1,2); System.out.println(x); Zlomek y = neu Zlomek(1,0); System.out.println(y); > class Zlomek { int čitatel, jmenovatel; public Zlomek(int c, int j) { // ujistíme se, že jmenovatel nebude nula assert j ?= B; > čitatel = c; jmenovatel = j; public String toStringO { return citatel+'V+jmenouatel; > Ukázka použití assert (2) Program přeložíme (s volbou - s o u r c e 1.4): Obrázek 1.2. Správný postup překladu AssertDemo 4 zy. I— Command Shell C:Stomp\pbl62\jaua>jauac —source 1.4 tomp/ucebnice/assertions/*.jaua C:StompNpbl62\jaua>_ -ln|x| Ukázka použití assert (3) Program spustíme (s volbou -ea nebo selektivním -ea: NázevTřidy): Obrázek 1.3. Spuštění AssertDemo s povolením assert Command Shell C:\tomp\pbl62\jaua>java -ea tomp/ucebnice/assertions/AssertDemo 1/2 Exception in thread "main" Java.lang. AssertionError at tonip.učebnice.assertions.Zlomek. at tomp.učebnice.assertions.AssertDemo.main(AssertDemo.jaua:9> C:Stomp\pbl62\jaua>_ ^Jnj_>jaua —da tomp/ucebnice/assertions/AssertDemo í/2 1/0 C:StompSpbl62Sjaua>_ Postup při práci s JUnit Uvědomit si, že žádný nástroj za nás nevymyslí, JAK máme své třídy testovat. Pouze nám napomůže ke snadnějšímu sestavení a spuštění testu. Postup: 1. Stáhnout si z http://junit.org poslední (stačí binární) distribuci testovacího prostředí. 2. Nainstalovat JUnit (stačí rozbalit do samostatného adresáře). 5 Přednáška 7 - testování a ladění programů, junit, assert. Javové operátory, složitější výra- Napsat testovací třídu/třídy - buďto implementují rozhraní j unit. framework. Test nebo ob-vykleji rovnou rozšiřují třídu junit. framework. TestCase Testovací třída obsahuje metodu na nastavení testu (setUp), testovací metody (testNeco) a úklidovou metodu (tearDown). Testovací třídu spustit v prostředí (řádkovém nebo GUI) - junit. textui .TestRunner, junit. swingui . TestRunner... 6. Testovač zobrazí, které testovací metody případně selhaly. Ukázka použití JUnit (1) Třída Zlomek zůstává zhruba jako v předchozím příkladu, přibývají však metody equals (porovnává dva zlomky, zda je jejich číselná hodnota stejná) a součet (sečítá dva zlomky, součet vrací jako výsledek). Obrázek 1.5. Upravená třída Zlomek s porovnáním a součtem JUnitDemo.java Assert.iava | } class Zlomek { int čitatel, jmenovatel; public Zlomek( c, int j) { assert j != 8; čitatel = c; jmenovatel = j; > public boolean equals(Object o) { if (o instanceof Zlomek) { Zlomek z = (Zlomek)o; return čitatel * z.jmenovatel == z.čitatel * jmenovatel; } else return false; > public static Zlomek soucet(Zlomek a, Zlomek b) { return new Zlomek(a.citatel*b.jmenovatel + b.citatel*a.jmenovatel, a.j menovatel*b.jmenovatel); > public String toStringO { return citatel+'V+jmenouatel; > 6 zy. Ukázka použití JUnit (2) Testovací třída JUnitDemo má „přípravnou" metodu setUp, tearDown a testovací metody. Obrázek 1.6. Testovací třída JUnitDemo JUnitDemo.Java Assert.java | package tomp.učebnice.junit; public class JUnitDemo extends junit.franeuork.TestCase { private Zlomek x, y, součet, xx; public uoid setUpO { x = new Zlomek(1,2); xx = new Zlomek( , 12); y = new Zlomek(1,3); součet = new Zlomek(5,6); } public uoid testRouna() { assertEquals("1/2 a 6/12 se musi rounat", x, xx); } public uoid testSoucetRounaO { Zlomek s = Zlomek.součet(x, y); assertEqualsC'Soucet 1/2 a 1/3 se musi rounat 5/6", součet, s); } public uoid testNelzeUytuoritO { try { Zlomek bad = new Zlomek(10,0); fail("Zlomek s nulouym jmenovatelem nemel jit uytuorif); } catch(HssertionError ae) { // OKÍ } } public uoid tearDownO { } Ukázka použití JUnit (3) Spuštění testovace v prostředí GUI Swing nad testovací třídou JUnitDemo. Obrázek 1.7. Spouštění testovace nad testovací třídou JUnitDemo 7 Přednáška 7 - testování a ladění programů, junit, assert. Javové operátory, složitější výra- I— Command Shell - Java -ea -classpath \devel\Junit3.S.l\iunit.iar;. junit.sviingui.TestRunner tomp.ucebn. Microsoft Uindous 2000 [Uersion 5.00.2195] Copyright 1985-2000 Microsoft Corp. ^Jöj-Kj C:StompNpbl62\jaua>jaua -ea -classpath \deuel\junit3.8.l\junit.jar;, ui.TestRunner tomp.ucebnice.junit.JUn itDeno junit.suing Pokud testovací třída prověří, že testovaná třída/y je/jsou OK, vypadá to přibližně takto: Obrázek 1.8. Testovač spouštějící třídu JUnitDemo J JUnit JUnit ^JnJjsJ Test class name: tomp.ucebnice.junit.JUnitDemo tomp.uc E Rela load classes every run Runs: 3/3 x Errors: 0 isults: I tomputebnicejunitJUnitDemo / testRovna / testSoutetRovna testN e lze Vytvořit x Failures jfc Test Hierarchy Finished: 0,03 seconds Run du K Failures: 0 Ukázka použití JUnit (4) Mä-li testovaná třída/y chyby a zjistí-li to testovač, vypadá to třeba takto: zy. Obrázek 1.9. Testovací třída JUnitDemo našla chybu JÜ JUnit JUnít JOLsl Test class name: tomp.ucebnice.junít.JUnítDemo tom El Ý\ Reload classes every run Runs: 3/3 x Errors: 0 K Failures: 1 Results: ff testSoucetRovna(toinp.ucebnice.junit.JUnitDetno):Soucet 1/; 4 x Failures £ Test Hierarchy junit.framework.AssertionFailedError: Součet 1/2 a 1/3 se inusi n attomp.ucebnice.junit.JUnitDemo.testSoucetRovna(JUnitDeiTio at sun.reflect.NativeMethodAccessorltnpl.invokeO(Native Method at sun.reflect.NativeMethodAccessorlmpl.invoke(NativeMethodAi at sun.reflect.DelegatingMethodAccessorlľnpl.invoke(Delegatinc Finished: 0,05 seconds Run Ju Run Exit Postup při práci s jass jass je preprocesor javového zdrojového textu. Umožňuje ve zdrojovém textu programu vyznačit podmínky, jejichž splnění je za běhu kontrolováno. 9 Přednáška 7 - testování a ladění programů, junit, assert. Javové operátory, složitější výra- Podmínkami se rozumí: • pre- a postconditions u metod (vstupní a výstupní podmínky metod) • invarianty objektů - podmínky, které zůstávají pro objekt v platnosti mezi jednotlivými operacemi nad objektem Postup práce sjass: stažení a instalace balíku z http://csd.informatik.uni-oldenburg.de/~jass/ • vytvoření zdrojového textu s příponou . j ass, javovou syntaxí s použitím speciálních komentářových značek • takový zdrojový text je přeložitelný i normálním překladačem javac, ale v takovém případě ztrácíme možnosti jass • proto nejprve .jass souboru převedeme preprocesorem jass na javový (. j ava) soubor • ten již přeložíme javac a spustíme java, tedy jako každý jiný zdrojový soubor v Jávě • z .jass zdrojů je možné vytvořit také dokumentaci API obsahující jass značky, tj. informace, co kde musí platit za podmínky atd. - vynikající možnost! Odkazy • JUnit homepage [http://junit.org] • Java 1.4 logging API guide [http://java.sun.eom/j2se/l.4.2/docs/guide/util/logging/] • Log4j homepage [http://jakarta.apache.org/log4j/docs/index.html] • jass homepage [http://csd.informatik.uni-oldenburg.de/~jass/] • úvodní materiálek [http://www.inf.fu-berlin.de/lehre/SS01/VIS/Dokumente/Vortraege/junit.pdf] k použití junit (v němčině, jako PDF) Operátory a výrazy, porovnávání objektů • Operátory v Jávě: aritmetické, logické, relační, bitové • Porovnávání primitivních hodnot a objektů, metody equals a hashCode Ternární operátor podmíněného výrazu Typové konverze 10 zy. Operátor zřetězení Aritmetické +,-,*,/ a % (zbytek po celočíselném dělení) Logické logické součiny (AND): & {nepodmíněný - vždy se vyhodnotí oba operandy), & & {podmíněný - líné vyhodnocování - drahý operand se vyhodnotí, jen nelze-li o výsledku rozhodnout z hodnoty prvního) logické součty (OR): | {nepodmíněný - vždy se vyhodnotí oba operandy), | | {podmíněný - líné vyhodnocování - drahý operand se vyhodnotí, jen nelze-li o výsledku rozhodnout z hodnoty prvního) negace (NOT): . i Relační (porovnávací) Tyto lze použít na porovnávání primitivních hodnot: < ,<= ,>= ,> Test na rovnost/nerovnost lze použít na porovnávání primitivních hodnot i objektů: • == i = Upozornění: • pozor na porovnávání objektů: == vrací true jen při rovnosti odkazů, tj. jsou-li objekty identické. Rovnost obsahu (tedy "rovnocennost") objektů se zjišťuje voláním metody ol.equals(Object o2) 11 Přednáška 7 - testování a ladění programů, junit, assert. Javové operátory, složitější výra- • pozor na srovnávání floating-points čísel na rovnost: je třeba počítat s chybami zaokrouhlení; místo porovnání na přesnou rovnost raději používejme jistou toleranci: abs(expected-actual) < delta Porovnávání objektů Použití == • Porovnáme-li dva objekty (tzn. odkazy na objekty) prostřednictvím operátoru == dostaneme rovnost jen v případě, jedná-li se o dva odkazy na tentýž objekt - tj. dva totožné objekty. • Jedná-li se o dva obsahově stejné objekty existující samostatně, pak == vrátí false. Chceme-li (intuitivně) chápat rovnost objektů podle obsahu, tj. dva objekty jsou rovné {rovnocenné, nikoli totožně), mají-li stejný obsah, pak • musíme pro danou třídu překrýt metodu equals, která musí vrátit true, právě když se obsah výchozího a srovnávaného objektu rovná. • Fungování equals lze srovnat s porovnáváním dvou databázových záznamů podle primárního klíče. Nepřekryjeme-li equals, funguje původní equals přísným způsobem, tj. rovné si budou jen totožné objekty. Porovnávání objektů - pnklad Příklad: objekt třídy Človek nese informace o člověku. Dva objekty položíme stejné (rovnocenné), ne-sou-li stejná příjmení: Obrázek 1.10. Dva lidi jsou stejní, mají-li stejná příjmení public class Človek implements Comparable { String jmeno, prijmeni; public Človek (String j, String p) { jmeno = j; prijmeni = p; } public boolean equals(Object o) { if (o instanceof Človek) { Človek c = (Človek)o; return prijmeni.equals(c.prijmeni); } else throw new IllegalArgumentException( 12 zy. "Nelze porovnat objekt typu Človek s objektem jiného typu"); } } } Méně agresivní verze by nemusela při porovnávání s jiným objektem než Človek vyhodit výjimku, pouze vrátit false. Metoda hashCode Jakmile u třídy překryjeme metodu equals, měli bychom současně překrýt objektů i metodu hashCode: • hashCode vrací celé číslo (int) „co nejlépe" charakterizující obsah objektu, tj. • pro dva stejné (equals) objekty musí vždy vrátit stejnou hodnotu. • Pro dva obsahově různé objekty by hashCode naopak měl vracet různé hodnoty (ale není to stoprocentně nezbytné a ani nemůže být vždy splněno). Metoda hashCode totiž nemůže vždy být prostá. Metoda hashCode - příklad V těle hashCode s oblibou „přehráváme" (delegujeme) řešení na volání hashCode jednotlivých složek objektu - a to těch, které figurují v equals: Obrázek 1.11. Třída Človek s metodami equals a hashCode public class Človek implements Comparable { String jmeno, prijmeni; public Človek (String j, String p) { jmeno = j; prijmeni = p; } public boolean equals(Object o) { if (o instanceof Človek) { Človek c = (Človek)o; return prijmeni.equals(c.prijmeni); } else throw new IllegalArgumentException( "Nelze porovnat objekt typu Človek s objektem jiného typu"); } public int hashCode() { return prijmeni.hashCode(); } 13 Přednáška 7 - testování a ladění programů, junit, assert. Javové operátory, složitější výra- Bitové Bitové: součin & součet | • exkluzivní součet (XOR) A (znak "stříška") • negace (bitwise-NOT) ~ (znak "tilda") Posuny: • vlevo «o stanovený počet bitů • vpravo »o stanovený počet bitů s respektováním znaménka • vpravo >» o stanovený počet bitů bez respektování znaménka Dále viz např. Bitové operátory [http://www.fi.muni.cz/~tomp/java/ucebnice/javasrc/tomp/ucebnice/operatory/Bitove.java] Operátor podmíněného výrazu ? : Jediný ternární operátor Platí-li první operand (má hodnotu true) -> • výsledkem je hodnota druhého operandu • jinak je výsledkem hodnota třetího operandu Typ prvního operandu musí být boolean, typy druhého a třetího musí být přiřaditelné do výsledku. Operátory typové konverze (pretypovaní) • Podobně jako v C/C++ • Píše se (typ)hodnota, např. (Clovek)o, kde o byla proměnná deklarovaná jako Object. • Pro objektové typy se ve skutečnosti nejedná o žádnou konverzi spojenou se změnou obsahu objektu, nýbrž pouze o potvrzení, že běhový typ objektu je požadovaného typu - např. (viz výše) že o je typu Človek. 14 zy. • Naproti tomu u primitivních typů se jedná o úpravu hodnoty - např. int pretypujeme na short a „ořeže" se tím rozsah. Operátor zřetězení + Výsledkem je vždy řetězec, ale argumenty mohou být i jiných typů, např. sekvence int i = 1; System, out .println ( "proměnna i="+i) ; je v pořádku s řetězcovou konstantou se spojí řetězcová podoba dalších argumentů (např. čísla). Pokud je argumentem zřetězení odkaz na objekt o -> • je-li o == null -> použije se řetězec null • je-li o ! = null -> použije se hodnota vrácená metodou o. toString () (tu lze překrýt a dosáhnout tak očekávaného řetězcového výstupu) Priority operátorů a vytváření výrazů nejvyšší prioritu má násobení, dělení, nejnižší přiřazení 15