Miloš Němec, osobní stránka

 Novinky Literatura Hudba Cestování a turistika Věda a technika Ostatní 
Domů > Věda a technika

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.

      Sociální záložky (?): linkuj.czfacebook.comtopclanky.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:
      • všechy vulgarity,
      • všechny příspěvky netýkající se tématu.
© 2003-2010 Miloš Němec. Všechna práva vyhrazena. Kontakt. Reklama. RSS 2.0 kanál (články) RSS