Proč testování?

  1. Teprve otestovaný a uživatelem akceptovaný program je v pořádku.

  2. Testování softwaru je klíčová součást vývoje - v podstatě ta nejdůležitější .

  3. Některé metodiky vývoje se o testování zásadně opírají: agilní metodiky obecně, konkrétně pak typicky Extreme Programming.

  4. Některé jsou jím přímo řízené — Test-Driven Development (vývoj řízený testy).

V čem spočívá testování?

  • Testování softwaru je mnohaúrovňový,

  • kontinuálně probíhající proces (v podstatě po celou dobu životního cyklu).

  • V případě tohoto předmětu testováním nemyslíme formální verifikaci (dokazování správnosti) programů, ale "pouze"

  • testování vybraných konkrétních případů běhu (case-based testing).

Úrovně testování?

  • Podle úrovně pohledu rozlišujeme testy:

    jednotek

    elementů programu, někdy i vytržených z kontextu - např. jednotlivých tříd a jejich souhry

    integrační

    určené k otestování právě integrované části kódu (např. po jeho změnách) do většího celku

    akceptační

    ověřují, zda je SW přijatelný pro uživatele/klienta

  • Zde se zatím zaměříme na testování jednotek, tedy malých celků, které budeme testovat izolovaně.

Co je testování jednotek?

  • Testování jednotek (unit testing) je první fází každého testovacího procesu.

  • Testuje jednotlivé elementární části kódu - v případě objektového světa třídy.

  • Často probíhá formou "black-box" testování (tzn. jen pohled z venku, tedy na veřejné vlastnosti — typicky metody), ale

  • může se kombinovat s nahlížením dovnitř objektů — např. na "package-local" metody a atributy, může testovat "package-local" třídy a rozhraní.

Jak probíhá v Javě

  • Pro testování jednotek obvykle používáme vhodný testovací rámec,

  • i když by šlo dělat i bez něj, vlastními ad-hoc vytvořenými nástroji.

  • v Javě se nejčastěji používá volně dostupný balík jUnit

  • existují jeho porty pro jiné jazyky/prostředí (C, C#, PHP, Perl,…)

  • pro Javu existují také koncepčně velmi podobné nebo i pokročilejší (ale zase méně známé) alternativy (TestNG)

  • starší verze (JUnit 3.x — ten již nepoužíváme) nepracovaly s tzv. anotacemi, novější již ano (JUnit 4.x)

  • novější mají též systematické pojmenovávání balíků a tříd — např. org.junit.Assert

Struktura testu v junit

Jednotkové testy v JUnit mají v zásadě tuto strukturu:

  • Elementárním testem je testovací metoda — její název začíná předponou test nebo je opatřena příslušnou anotací @Test (JUnit 4.x) nebo obojí.

  • Elementární testy se dají skládat do souborů testů, test suites.

Postup vykonání testu

  • Vykonání tohoto elementárního testu probíhá následovně:

    1. konstrukce objektu testu, tj. instance testovací třídy;

    2. inicializace testu metodou setUp (nebo i jinou metodou anotovanou @Before) —  taková metoda obvykle vytvoří tzv. testovací přípravek (fixture);

    3. proběhne příslušná (jedna z) testovací metoda;

    4. test je "uklizen" voláním metody tearDown nebo metodou anotovanou @After.

Note

Inicializační a uklizecí metody, stejně jako metody testu mají ve sterších JUnit (3.x) napevno předepsané názvy nebo přípony. Od 4.x lze označit anotacemi - ale pro přehlednost se jmenné konvence drží nadále.

Příklad

Testovaná třída Calculator, jednoduchá sčítačka čísel

public class Calculator {
   public int evaluate(String expression) {
      int sum = 0;
      for (String summand: expression.split("\\+"))
         sum += Integer.valueOf(summand);
      return sum;
   }
}

Testovací třída CalculatorTest

import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class CalculatorTest {
   @Test // takto značíme testovací metodu
   public void evaluatesExpression() {
      Calculator calculator = new Calculator();
      int sum = calculator.evaluate("1+2+3");
      assertEquals(6, sum); // takto ověřujeme, zda se suma rovná
   }
}

Spuštění testu

překlad testu

javac -cp .:junit-4.XX.jar CalculatorTest.java

spuštění testu

java -cp .:junit-4.XX.jar:hamcrest-core-1.3.jar org.junit.runner.JUnitCore CalculatorTest

výstup
JUnit version 4.12
.
Time: 0,006
OK (1 test)
Note

Lze také (a typičtěji se tak děje) spustit test přímo v integrovaném vývojovém prostředí (NetBeans apod.).

Označení metody za testovací: @Test

  • Stručně: lze použít následující anotace (konstrukce s @)

  • @Test před metodou označí tuto metodu za testovací.

  • Metoda se nemusí nijak speciálně jmenovat (žádné testXXX).

    @Test
    public void addition() {
       assertEquals(12, simpleMath.add(7, 5));
    }

Provedení před a po testu: @Before a @After

  • Metoda anotovaná @Before bude spuštěna před každým testem.

  • Obdobně metoda s @After po každém testu.

  • Ve starších verzích JUnit se užívaly metody setup a tearDown.

    @Before
    public void runBeforeEveryTest() {
       simpleMath = new SimpleMath();
    }

Očekávání výjimky

  • Takto označená metoda očekává, že v ní vznikne výjimka uvedeného typu.

  • Nestane-li se tak,test selže.

    @Test(expected = ArithmeticException.class)
    public void divisionWithException() {
       // divide by zero
       simpleMath.divide(1, 0);
    }

Dočasné vynechání: @Ignore

  • Označením @Ignore (obvykle dočasně) testovací metodu vyloučíme z provádění.

  • Lze uvést vysvětlující hlášku.

    @Ignore(“Not Ready to Run”)
    @Test
    public void multiplication() {
       assertEquals(15, simpleMath.multiply(3, 5));
    }

Časový limit testu

  • Bude-li u takto anotované metody při spuštění testu překročen časový limit, test selže.

  • Časový limit je v milisekundách.

    @Test(timeout = 1000)
    public void infinity() {
       while (true)
       ;
    }