Java: Poznámky z letmého průzkumu frameworku JUnit
JUnit Assert metody
public class MyClass { public int soucet(int a, int b) { return a+b; } }
import org.junit.*; public class MyClassTest { // ... @Test public void testSoucet() { int a=5; int b=8; MyClass instance = new MyClass(); int result = instance.soucet(a, b); int expResult = 13; assertEquals(expResult, result); } }
Assert metody:
assertEquals(...) assertArrayEquals(...) assertTrue/False(...) assert(Not)Null(...) assert(Not)Same(...) assertThat(...)
Vybrané příklady použití
Collection collection = new ArrayList();
assertTrue(collection.isEmpty());
Rozdíl mezi assertSame(...) a assertEquals(...)
assertSame(...) používá pro porovnání == (porovnání referencí), assertEquals(...) používá metodu equals(). Nemáme-li metodu equals() v našem objektu implementovanou, pak je každá instance rovna pouze sama sobě.
Naše equals() by měla vracet true pro dvě různé instance se stejným obsahem (porovnáním klíčových prvků).
Příklad implementace metody equals():
public class Point { private int x, y; // ... public boolean equals(Object other) { if (other == this) return true; if (!(other instanceof Point)) return false; Point point = (Point)other; return x == point.x && y == point.y; } }
assertThat(...)
assertThat([value], [matcher statement]);
Druhý parametr je Matcher, lze použít org.junit.matchers.JUnitMatchers, nebo jinou externí knihovnu (static import).
assertThat(x, is(3)); assertThat(x, is(not(4))); assertThat(responseString, either(containsString("color")).or(containsString("colour"))); assertThat(myList, hasItem("3"));
Předpoklady (Assumptions)
Předpoklady slouží k explicitnímu vyjádření podmínek (rozsah vstupních dat testu, dostupnost db připojení, nastavení systémové property apod.), za jakých test musí projít.
@Test public void filenameIncludesUsername() { assumeThat(File.separatorChar, is('/')); assertThat(new User("optimus").configFileName(), is("configfiles/optimus.cfg")); }
Neplatí-li předpoklad, je celý test označen jako úspěšný.
Teorie (Theories)
Teorie se skládá ze vstupních testovacích dat, předpokladu za kterého je schopen test s daty pracovat a vlastního testu.
@RunWith(Theories.class) public class UserTest { @DataPoint public static String GoodUsername = "optimus"; @DataPoint public static String UsernameWithSlash = "optimus/prime"; @Theory public void testUserFile(String username) { assumeThat(username, not(containsString("/"))); assertThat(new User(username).configFileName(), containsString(username)); } }
Anotace @DataPoint definuje vstupní data teorie. Metoda testUserFile je pak volána se všemi vstupními daty s odpovídajícím datovým typem. Samotný assert se navíc neprovádí s daty, pro která neplatí předpoklad.
Má-li testovací metoda více vstupních parametrů, použijí se všechny kombinace.
Sofistikovanější krmení daty lze zařídit implementací potomka třídy ParameterSupplier.
Chybová zpráva
Každý assert lze doplnit i o chybovou zprávu, která je vypsána pokud test selže.
assertEquals(message, expResult, result);
SetUp a TearDown
Pro nezbytně nutné inicializace a úklid jsou následující metody:
@BeforeClass public static void setUpClass() throws Exception { // zavolá se jednou - na začátku testování } @AfterClass public static void tearDownClass() throws Exception { // zavolá se po skončení posledního testu } @Before public void setUp() { // zavolá se před každým testem } @After public void tearDown() { // zavolá se po skončení každého testu }
Jak testovat private metody?
Netestovat
Private metody netestovat. Každá private metoda musí být volána public metodou. Pokud nelze jednoduše provést test pomocí public metod, něco v objektovém návrhu je špatně a pravděpodobně by bylo dobré private metodu převést do jiné třídy s modifikátorem public.
Využít Java Reflection API
/** * Convenient method to execute private methods from other classes. * @param test Instance of the class we want to test * @param methodName Name of the method we want to test * @param params Arguments we want to pass to the method * @return Object with the result of the executed method * @throws Exception */ private Object invokePrivateMethod (Object test, String methodName, Object params[]) throws Exception { Object ret = null; final Method[] methods = test.getClass().getDeclaredMethods(); for (int i = 0; i < methods.length; ++i) { if (methods[i].getName().equals(methodName)) { methods[i].setAccessible(true); ret = methods[i].invoke(test, params); break; } } return ret; }
MyClass instance = new MyClass(); String expResult = "Expected Result"; Object[] params = {"A String Value", "Another Value"}; String result = (String) this.invokePrivateMethod(instance, "myPrivateName", params); assertEquals(expResult, result);
methods[i].setAccessible(true)... lze také udělat např. v @Before bloku
Pro každou private metodu vytvořit public testovací volání
private int foo() { // ... } public int foo_FOR_TESTING_ONLY() { return foo(); }
Fuj!
Automatizace testů v NetBeans IDE
NetBeans IDE umožňuje:
- generování kostry testovacích tříd,
- spouštění všech, nebo jen vybraných testů,
- přehledné zobrazení výsledků testů s prokliky do kódu.
Postrádám:
- nějakou formu upozornění, že pro danou public metodu neexistuje test (pro měření pokrytí kódu testy ale lze využít frameworku Cobertura).
Závěr
Argumenty pro zavedení testů:
- jednotkové testy většinou zlepšují design aplikace, protože vývojáři jsou nuceni programovat s ohledem na snadnou testovatelnost – loose coupling (volné vazby, minimalizace závislostí).
Argumenty proti zavedení testů:
- dle prvních pokusů zabere napsání testů cca 30% vývojového času,
- psaní testů je "otravná" práce.
- všechy vulgarity,
- všechny příspěvky netýkající se tématu.
Sociální záložky (?):
linkuj.czfacebook.com
topclanky.cz
Tento článek si od 27. 7. 2010 přečetlo 71 čtenářů.
Diskuze:
V dizkuzi zatím nejsou žádné příspěvky.
Než přidáte svůj příspěvek, mějte prosím na zřeteli, že budou smazány:
