ݺߣ

ݺߣShare a Scribd company logo
Legéndi Richárd Olivér
             AITIA Szeminárium
                 rlegendi@aitia.ai
http://people.inf.elte.hu/legendi/
                    2012. május 25.
Szoftver tesztelés - Gyakorlati jó-ha-tudod
Áttekintkés
 Miért?
 Honnan jön?
 Kik?
 Hogyan?
 Hol használják aktívan?
 Mit követel meg?
 Toolok
    Ami belefér 
Miért?
 Quality
 Ami nektek, a fejlesztőknek fontos:
    Bizalom a saját kódodban
    Refactor: Nem félsz változtatni
       Nem fogod elbaszni, a teszted megfogja, ha valamit eltörtél!
   Hype téma, csapból is ez folyi
       Boldog-boldogtalan tesztkörnyezeteket ír
   Tanuló tesztek, határvonalak tisztán tartása, regression
    tesztek (megoldott issue ne jöhessen vissza), etc.
Honnan jön: RoR
 Agilis srácok
 Irgalmatlan egyszerű használni:

   test "login with invalid credentials" do
      post :login => {
        :user_name => 'foo',
        :password =>'bar‚
      }
      assert_equals flash[:error] , "Authentication failed"
    end
Kik?
 Tesztvezérelt-fejlesztés (TDD) és a Behaviour Driven
 Development (BDD, végrehajtható specifikáció)
 elkötelezett hívei (v.ö. eXtreme Programming: nincs
 terv, kódolnak egyből).
Hogyan?




Forrás: http://www.javacodegeeks.com/2012/05/test-driven-development-win-win.html
Hogyan?
 A TDD három alapelve:
  1. Nem írsz tényleges kódot, amíg nem írtál hozzá
     tesztet.
  2. A tesztből annyit írsz meg, amennyi a kudarchoz elég
     (ha nem fordul pl., az már kudarc).
  3. A tényleges kódból csak annyit írsz meg, ami elég a
     teszt sikeres teljesítéséhez.
 „TDD-ciklus”: Test  Code  Refactor
 A teszt és production kód szimbiózisban születik
Milyen?
 F.I.R.S.T. alapelvek:
    Fast - Ha lassú, nem futtatod.
    Independent - Ha függőség van, hibát rejthet el.
    Repeatable - Bárhol megismételhető (minden
     fejlesztőnél reprodukálható legyen a hiba).
    Self-validating - Ha kézzel kell hasonlítgatnod a teszt
     eredményét, úgysem fogsz vele foglalkozni.
    Timely - Rég nem támogatott API funkciók tesztje
     teljesen felesleges.
Mit követel meg?
 A tervezést, kódstrukturát is átalakítja.
 Kicsit más kódszervezés kell
  (mellékhatások elkerülése - azt nem tudod tesztelni)
 Sok POJO, minimális funkcionalitással
  (azt könnyű tesztelni)
Mit követel meg?
 Egyéb apróságok, pl. lazy instantiationt kidobni
 (premature optimalizáció)
   Osztály nem vállalja fel a másodlagos feladatokat
    (Single Resp. Princ.)
   Helyette inkább IoC/Dep. Inj.
    (AOP keretek, akkor hozza létre, amikor kell)
Tesztek fajtái
 Mindre nézünk toolt:
   Unit: ~POJO-k
   Functional: ~project
   Integration: ~full stack
        Embedded DB + in-proc. web server + JWebUnit/Selenium
    Acceptance: ~„user story”
Szoftver tesztelés - Gyakorlati jó-ha-tudod
Toolok
 Özönvíz (pun intended )
   http://www.opensourcetesting.org/unit_java.php
   70 külön lib/framework/tool...
Assert
 Lerágott csont, de szerintem hasznos 
 Control-flow invariant, etc.
 Nem egy DbC facility, de hasznos:
   Internal Invariants
   Control-Flow Invariants
   Preconditions, Postconditions, and Class Invariants

http://docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.html
Unit tesztek
 Egységek (pl. modellek) tesztelésére
 Tonnányi keretrendszer (JUnit/TestNG/...)
 Kent Beck (XP megalkotója, Agile demigod), Erich
 Gamma (hasonló kaliberű úriember, pl. Eclipse JDT-
 ben volt benne a keze) haxolta össze egy repülőgépen a
 JUnit első verzióját.
Példa
public class Utils {
    public static int sum(int[] arr) {
        if (null == arr) {
            throw new IllegalArgumentException("arr == null");
        }

        int sum = 0;
        for (int i : arr) {
            sum += i;
        }

        return sum;
    }
}
Tesztek (JUnit 4.x)
import org.junit.* ;
import static org.junit.Assert.* ;

public class UtilsTest {
  @Test
  public void assertSumForZeroArray() {
    final int[] arr = new int[0];      // Given
    final int actual = Utils.sum(arr); // When

        final int expected = 0;     // Then
        assertEquals("Sum of empty array must be zero.", expected, actual);
    }

    @Test(expected=IllegalArgumentException.class)
    public void assertForIllegalArgument() {
      Utils.sum(null);
    }
}
Egyéb hasznos annotációk
@Ignore("John broke this yesterday")            @Test(timeout=1000)
@Test                                           public void
public void                                     someMethodThatShouldRunInAMinute() {
someBuggyOrUnimplementedTest() {                  // ...
  // ...                                        }
}
                                                @Before
@BeforeClass                                    public void beforeEachTest() {
public void initializeStuffBeforeAnyTests() {     // ...
  // ...                                        }
}
                                                @After
@AfterClass                                     public void afterEachTest() {
public void cleanupStuffAfterAllTests() {         // ...
  // ...                                        }
}
Egyéb hasznos assert utasítások
   assertTrue(...);               Tonnányi egyéb
   assertFalse();                 Ld. Assert javadoc
   fail();
   assertEquals(...);
   assertArrayEquals(...);
   assertEquals(...);
   assertNotNull(...);
   assertNull(...);
   assertSame(...);
   assertNotSame(...);
   assertEquals(...);
   assertThat(...); // Matcher
Common Pitfalls
 Egy teszt-egy állítás (nem feltétlen egy assert utasítás)
 Teszttel is játsz egy kicsit! Az is kód, abban is annyira bízz...
 Triviális tesztek!
     Triviális hibakeresés
 Ajánlás: tényleges kód és a tesztek külön source mappában
  (production kódban semmi helye, tisztességes build tooloknál ez
  alap)
 Láthatóság: a legritkább esetben oldjuk fel tesztek miatt. Legyen
  ez az utolsó, amivel próbálkozunk!
 Vigyázat, 2 JUnit osztály van! A másik legacy...
 Randomizálás? Inkább ne...  Mutation testing
 assertTrue(actual == 0) !=
        assertEquals(expected, actual)
IDE Integráció
 Eclipse
    Hozzáadás: Project jobklikk -> Properties -> Java Build
     Path -> Libraries -> Add Library -> JUnit -> JUnit 4
     (alapból benne van)
    Futtatás: Jobklikk -> Run As... -> JUnit
 NetBeans
    Alapból benne van egy egyszerű Java projectben.
Egyéb Toolok
Mocking
 Motiváció: adatbázis nincs...
 DAO-s példa: van interfész, van JdbcDao
  implementáció, aztán meg Test1Dao implementáció...
 DE! Helyette: lehet mockolni, ügyes cuccok
  (Néha már-már internal DSL benyomását keltő toolok)
 Ebből is van egy pár...
Mocking frameworkök – ízelítő




http://code.google.com/p/jmockit/wiki/MockingToolkitComparisonMatrix
Mocking: Példa
public void testBobsLogin() {
    User results = new User();
    String userName = "bob";
    String password = "bob1234";
    String passwordHash = "0340e21833f1291f673fcaab8d13";

    expect(mockDao.queryUserData(userName, passwordHash))
                .andReturn(results);

    replay(mockDao);
    assertTrue(service.login(userName, password));
    verify(mockDao);
}
Tonnányi egyéb feature
 Ellenőrzések
    Hívások min/max/pontos száma
    Sorrendiség
 Részleges mockolás
    Spy: adott függvények kiütésére
 Viselkedés felvétele, visszajátszása, ellenőrzése
 ...
PowerMock
 Ha elértük a korlátokat, "jó lenne..." funkciók
 Támogat több platformot
    Mockito/EasyMock/...
 Példák:
    statikus függvények mockolása
    final classok mockolása
    ...
Hamcrest
 Matcher library (innen a név)
 "Literate programming" (Knuth, 1970)
 Példával a legkönnyebb megérteni:
   assertThat("Ray went to holiday",
      developers.getRay().countReadBooks(), equalTo(10));
   assertThat(Math.sqrt(-1), is(notANumber()));

 A BDD-s srácok nagyon szeretik
 Kényelmi funkcionalitása van
Design by Contract
 Eiffel – Bertrand Meyer
 Minden komponensnek contractja van
  (Nem is áll olyan messze tőlünk, ld. equals(), hashCode()
  Javadocját!)
 Ebből is van tonnányi, 3 példa:
    comment, annotációs, konfigurációs osztályos
 Invariáns, elő- és utófeltételek
 Assertekkel kiváltható? Nem igazán...
 AspectJ-vel lehet játszani egy szintig, de...
 Hol hasznos? Pl. szervleteknél ott, ahol macera a tesztelés
Példa
@Invariant("getCount() >= 0")
public interface Stack<E> {

    int getCount();

    ...

    @Ensure("{result}==(getCount()==0)")
    public boolean isEmpty();

    @Require("getCount() > 0 ")
    @Ensure("getCount() == {old getCount()} - 1 ")
    void remove();
}
Code coverage
 Nagyobb projectnél könnyű elveszteni, mit mennyire
  teszteltünk
 Megoldás: Code coverage (számtalan definíció szerint)
 Reneteg tool, pl. Clover, Cobertura (generált doksik
  királyak)
 Vannak pluginok az IDE-kben, pl. EclEmma
Code coverage
 Maximizálni érdemes, nem érdemes?
    Nem biztos, hogy megéri a 100%-ra hajtani - bár láttam
     már ilyet (és nem is mindig megoldható, pl.
     BufferedReadert megfelelően használni lehetetlen)
    Néha meg a 400% is kevés...
 Koncentráljunk a lényeges komponensekre
Continuous Integration rendszerek
 Rengeteg tool: Hudson, Jenkins, Bamboo, ...
 Mikor?
   Ha sok teszt van, és nem elég a GridGain farm pl.
    Unit tesztek gyorsan lefutnak, de lehetnek sokan.
   Integráció! pl. cm/inch
   Kapható/építhető build status jelző 
    http://hackaday.com/2011/04/12/led-build-monitor-helps-keep-an-eye-on-your-servers/
Sonar
 Mindenféle statisztikák - a trend miatt fontos.
 Összekötve a CI rendszerrel
 Mutatja a tesztelésre szoruló részeket
 Tonnányi projecthez példa:
    http://nemo.sonarsource.org/
Acceptance tesztek
 Rengeteg tool, framework, pl. FitNesse, Specs2
 Decision table egy Wikibe  Teszt, minimális kóddal
 Átruházható a tesztírás a kliensre
    Haha...
Példa: FitNesse
 Wiki:

   |eg.Division|
   |numerator|denominator|quotient?|
   |10       |2          |5        |
   |12.6     |3          |4.2      |
   |100      |4          |33       |

 Kell hozzá egy minimális Java osztály, 3 adattaggal
 Lesz egy nagy zöld „Teszt” gomb
 Meg lehet nyomni 

Példa: http://fitnesse.org/FitNesse.UserGuide.TwoMinuteExample
Példa: Specs2 Forms
BDD
 Wiki:
   BDD is a second-generation, outside–in, pull-based,
    multiple-stakeholder, multiple-scale, high-automation,
    agile methodology. It describes a cycle of interactions
    with well-defined outputs, resulting in the delivery of
    working, tested software that matters.
 Magyarul: értse meg a nem kóder is a teszteket 
DSL – Scala, Specs1/2
 class HelloWorldSpec extends Specification {

     "The 'Hello world' string" should {
       "contain 11 characters" in {
         "Hello world" must have size(11)
       }
       "start with 'Hello'" in {
         "Hello world" must startWith("Hello")
       }
       "end with 'world'" in {
         "Hello world" must endWith("world")
       }
     }
 }
                           Forrás: http://etorreborre.github.com/specs2/
DSL – Scala, Specs2
import org.specs2._

class HelloWorldSpec extends Specification { def is =

    "This is a specification to check the 'Hello world' string"   ^
                                                                  p^
    "The 'Hello world' string should"                             ^
      "contain 11 characters"                                     ! e1^
      "start with 'Hello'"                                        ! e2^
      "end with 'world'"                                          ! e3^
                                                                  end

    def e1 = "Hello world" must have size(11)
    def e2 = "Hello world" must startWith("Hello")
    def e3 = "Hello world" must endWith("world")
}
DSL – Groovy (Spock)
@Unroll
void "Ship goes to red alert only when enemy charges weapons"() {
    given:
    CommandComputer commandComputer = new CommandComputer()

    and:                                                       ~JUnit Theories, de egyszerűbb
    when:                                                      szintakszissal
    commandComputer.updateFromSensors(sensorReading)
                                                          Forrás: http://sett.ociweb.com/sett/settFeb2012.html
    then:
    commandComputer.getAlertStatus() == expectedAlertStatus

    where:
    entityType   << [EntityType.SHIP,       EntityType.ANOMALY]
    powerReading << [PowerReading.HIGH,     PowerReading.LOW]
    friendOrFoe << [FriendOrFoe.FOE,        FriendOrFoe.UNKNOWN]
    powerType    << [PowerType.WEAPONS,     PowerType.RADIATION]
    direction    << [Direction.TOWARD_SHIP, Direction.AWAY_FROM_SHIP]
    expectedAlertStatus << [AlertStatus.RED, AlertStatus.GREEN]
}
DSL – Groovy (Spock)
void "red alert causes shields be raised with the correct shield frequency"() {
    given:
    EnvironmentSystem environmentSystem = Mock(EnvironmentSystem)
    ShieldSystem shieldSystem = Mock(ShieldSystem)

    CommandComputer commandComputer = new CommandComputer()
    commandComputer.setEnvironmentSystem(environmentSystem)
    commandComputer.setShieldSystem(shieldSystem)

    when:
    String result = commandComputer.execute("Red Alert")

    then:
    1 * shieldSystem.raiseShields({int shieldFrequency ->
        shieldFrequency == commandComputer.getShieldFrequency()
    }) >> 100

    result.contains("Shield Strength 100%")
}
UI Testing
 Számtalan változat:
    WindowsTester
    Jubula (Eclipse-ben alapból van már)
    FEST
    Jemmy
    Maveryx
    ...
Selenium (Play!)
#{selenium 'Test security'}

   clearSession()
   open('/admin')
   assertTextPresent('Login')

   type('login', 'admin')
   type('password', '12345')
   clickAndWait('signin')

   assertText('success', 'Welcom admin!')

#{/selenium}
Selenium – Java API
WebDriver driver = new FirefoxDriver();

driver.get("http://www.google.com");

WebElement element = driver.findElement(By.name("q"));
element.sendKeys("Cheese!");
element.submit();

// Wait for the page to load, timeout after 10 seconds
(new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() {
    public Boolean apply(WebDriver d) {
        return d.getTitle().toLowerCase().startsWith("cheese!");
    }
});

driver.quit();
Egyéb hasznos toolok
 FindBugs – meglepődtök majd...
 PMD/CMD
    Patternek, ajánlások
    Copy & paste kódok kiszűrése


 Ant/Maven targetek, GUI-s alkalmazás, Eclipse plugin
Amiről nem esett szó, de jó lenne...
 Stressz-teszt
    JMeter
     http://netbeans.org/kb/docs/javaee/ecommerce/test-profile.html
 Selenium IDE
 Mutation testing: kipróbálod, szar, tényleg reccsen? (pl. PIT, a
  JUnitos srácok csinálják)
 JUnit:
    Theories, experimental feature-ök
    Data tables
 Arquillian (JBoss test framework)
 Security testing:
    Acuentix WebVulnerability Scanner, SQL Ninja, Tenable Nessus, ...
Összefoglalás
 Megéri? Kódot megírni ~t idő, tesztelve megírni ~3t
 DE! 2-3 manuális teszt után már egyértelműen megéri
  a befektetés (szerintem)
 Tekintve, hogy p megírás, q fenntartás, és p <<< q...
Összefoglalás
 Saját tapasztalat:
    Kb. mindegy, melyik toolt használod, csak használd!
    Megszünnek a napokig tartó debuggolások
    Nem félsz hozzányúlni a kódhoz
    Nem elfelejteni: a tesztkód írása ugyanolyan fegyelmet
     követel a fejlesztőtől, mint a tényleges kód írása...
    Ha megszokod, nem kód többé, amihez nincs teszt
     (pl. R-ben is csak tesztekkel írok scriptet)
    Tesztet írni fun – kielégíti az ember lelkének
     gonoszkodó kis részét 
    Jó, ha van 3 környezet: dev – test – prod
Megjegyzések
 Metrikák: nem túl hasznosak, korrelálnak a LoC-dal
 Sonar: „minőségi mutatók”
 Könyvajánló:
 Robert C. Martin: Clean Code: A
 Handbook of Agile Software
 Craftsmanship
 Martin J. Fowler et al.: Refactoring
 Improving the Design of Existing Code
éé
Szoftver tesztelés - Gyakorlati jó-ha-tudod
Köszönöm a figyelmet!

             Legéndi Richárd Olivér
               AITIA Szeminárium
                rlegendi@aitia.ai
        http://people.inf.elte.hu/legendi/
                 2012. május 25.
Demo
 Eclipse: JUnit hozzáadása, futtatása
 Eclipse: Code coverage mutogatása
 Sonar: EDN project
 Crisis: Mark 1 Jenkins-project
 Generált Maven doksi
    Code coverage

More Related Content

Similar to Szoftver tesztelés - Gyakorlati jó-ha-tudod (20)

PPTX
Funkcionális tesztelés támogatása UFT tesztautomatizálással
Gergő Hencz
PDF
Több app fejlesztése egy kódbázisból Androidon
Richard Radics
PDF
Jee kurzus 2. het
Janos Seteny
PPTX
Teszt alapú fejlesztés
vvinston
PDF
Jee kurzus 4. het
Janos Seteny
PPTX
Tesztelesi folyamatok - Arkon
zferenczik
PDF
Jee kurzus 3. het
Janos Seteny
PPTX
Modell alapú tesztelés: célok és lehetőségek
Zoltan Micskei
PDF
A tesztelés szerepe folyamatos kihelyezést használó projektekben (Microsoft, ...
Gáspár Nagy
PDF
Hogyan segítenek a felhasználók mobil appot fejleszteni? A crowdtestingről rö...
Balázs Fónagy
PPTX
Hogyan segítenek a felhasználók mobil appot fejleszteni? A crowdtesting röviden.
Balázs Fónagy
PPTX
Szerver oldali fejlesztés korszerű módszerekkel C# nyelven
Krisztián Gyula Tóth
PDF
python-metaprogramozas
Viktor Hercinger
ODP
Alumni Release Process
Gábor Nagymajtényi
PDF
Hello BDD @ WebConf/2013
Zoltán Szász
PDF
Forráskódtárak gráfalapú statikus analízise
Dániel Stein
PDF
PHP alkalmazások minőségbiztosítása
Ferenc Kovács
PPTX
Behavior Driven Development Specflow-val
Tamás Árpád
PPTX
Vágyak tesztelése a gyakorlatban
Orsolya Bánki
PPTX
Ci
nagno
Funkcionális tesztelés támogatása UFT tesztautomatizálással
Gergő Hencz
Több app fejlesztése egy kódbázisból Androidon
Richard Radics
Jee kurzus 2. het
Janos Seteny
Teszt alapú fejlesztés
vvinston
Jee kurzus 4. het
Janos Seteny
Tesztelesi folyamatok - Arkon
zferenczik
Jee kurzus 3. het
Janos Seteny
Modell alapú tesztelés: célok és lehetőségek
Zoltan Micskei
A tesztelés szerepe folyamatos kihelyezést használó projektekben (Microsoft, ...
Gáspár Nagy
Hogyan segítenek a felhasználók mobil appot fejleszteni? A crowdtestingről rö...
Balázs Fónagy
Hogyan segítenek a felhasználók mobil appot fejleszteni? A crowdtesting röviden.
Balázs Fónagy
Szerver oldali fejlesztés korszerű módszerekkel C# nyelven
Krisztián Gyula Tóth
python-metaprogramozas
Viktor Hercinger
Alumni Release Process
Gábor Nagymajtényi
Hello BDD @ WebConf/2013
Zoltán Szász
Forráskódtárak gráfalapú statikus analízise
Dániel Stein
PHP alkalmazások minőségbiztosítása
Ferenc Kovács
Behavior Driven Development Specflow-val
Tamás Árpád
Vágyak tesztelése a gyakorlatban
Orsolya Bánki

More from Richard Oliver Legendi (10)

PPTX
Tools For Statistical And Behavioral Analysis Of Mason Models
Richard Oliver Legendi
PPTX
When Experimental and Computational Research Meet: The Participatory Extensio...
Richard Oliver Legendi
PPTX
Comparison of Elementary Dynamic Network Models Using Empirical Data
Richard Oliver Legendi
PPTX
Model Replication in the Context of Agent-based Simulation
Richard Oliver Legendi
PPTX
Replication of Macroeconomics from the Bottom-up
Richard Oliver Legendi
PPTX
ELTE VI. féléves doktori beszámoló
Richard Oliver Legendi
PPT
Fables - Funkcionális programozási nyelv ágens-alapú szimulációkhoz
Richard Oliver Legendi
PPT
FABLES IME - Agent-Based Modeling environment
Richard Oliver Legendi
PPTX
2011 Eclipse DemoCamp Budapest, Indigo Release
Richard Oliver Legendi
PPTX
2010/04/28 IK Szakest, Ágens-alapú szimulációk
Richard Oliver Legendi
Tools For Statistical And Behavioral Analysis Of Mason Models
Richard Oliver Legendi
When Experimental and Computational Research Meet: The Participatory Extensio...
Richard Oliver Legendi
Comparison of Elementary Dynamic Network Models Using Empirical Data
Richard Oliver Legendi
Model Replication in the Context of Agent-based Simulation
Richard Oliver Legendi
Replication of Macroeconomics from the Bottom-up
Richard Oliver Legendi
ELTE VI. féléves doktori beszámoló
Richard Oliver Legendi
Fables - Funkcionális programozási nyelv ágens-alapú szimulációkhoz
Richard Oliver Legendi
FABLES IME - Agent-Based Modeling environment
Richard Oliver Legendi
2011 Eclipse DemoCamp Budapest, Indigo Release
Richard Oliver Legendi
2010/04/28 IK Szakest, Ágens-alapú szimulációk
Richard Oliver Legendi
Ad

Szoftver tesztelés - Gyakorlati jó-ha-tudod

  • 1. Legéndi Richárd Olivér AITIA Szeminárium rlegendi@aitia.ai http://people.inf.elte.hu/legendi/ 2012. május 25.
  • 3. Áttekintkés  Miért?  Honnan jön?  Kik?  Hogyan?  Hol használják aktívan?  Mit követel meg?  Toolok  Ami belefér 
  • 4. Miért?  Quality  Ami nektek, a fejlesztőknek fontos:  Bizalom a saját kódodban  Refactor: Nem félsz változtatni  Nem fogod elbaszni, a teszted megfogja, ha valamit eltörtél!  Hype téma, csapból is ez folyi  Boldog-boldogtalan tesztkörnyezeteket ír  Tanuló tesztek, határvonalak tisztán tartása, regression tesztek (megoldott issue ne jöhessen vissza), etc.
  • 5. Honnan jön: RoR  Agilis srácok  Irgalmatlan egyszerű használni: test "login with invalid credentials" do post :login => { :user_name => 'foo', :password =>'bar‚ } assert_equals flash[:error] , "Authentication failed" end
  • 6. Kik?  Tesztvezérelt-fejlesztés (TDD) és a Behaviour Driven Development (BDD, végrehajtható specifikáció) elkötelezett hívei (v.ö. eXtreme Programming: nincs terv, kódolnak egyből).
  • 8. Hogyan?  A TDD három alapelve: 1. Nem írsz tényleges kódot, amíg nem írtál hozzá tesztet. 2. A tesztből annyit írsz meg, amennyi a kudarchoz elég (ha nem fordul pl., az már kudarc). 3. A tényleges kódból csak annyit írsz meg, ami elég a teszt sikeres teljesítéséhez.  „TDD-ciklus”: Test  Code  Refactor  A teszt és production kód szimbiózisban születik
  • 9. Milyen?  F.I.R.S.T. alapelvek:  Fast - Ha lassú, nem futtatod.  Independent - Ha függőség van, hibát rejthet el.  Repeatable - Bárhol megismételhető (minden fejlesztőnél reprodukálható legyen a hiba).  Self-validating - Ha kézzel kell hasonlítgatnod a teszt eredményét, úgysem fogsz vele foglalkozni.  Timely - Rég nem támogatott API funkciók tesztje teljesen felesleges.
  • 10. Mit követel meg?  A tervezést, kódstrukturát is átalakítja.  Kicsit más kódszervezés kell (mellékhatások elkerülése - azt nem tudod tesztelni)  Sok POJO, minimális funkcionalitással (azt könnyű tesztelni)
  • 11. Mit követel meg?  Egyéb apróságok, pl. lazy instantiationt kidobni (premature optimalizáció)  Osztály nem vállalja fel a másodlagos feladatokat (Single Resp. Princ.)  Helyette inkább IoC/Dep. Inj. (AOP keretek, akkor hozza létre, amikor kell)
  • 12. Tesztek fajtái  Mindre nézünk toolt:  Unit: ~POJO-k  Functional: ~project  Integration: ~full stack  Embedded DB + in-proc. web server + JWebUnit/Selenium  Acceptance: ~„user story”
  • 14. Toolok  Özönvíz (pun intended )  http://www.opensourcetesting.org/unit_java.php  70 külön lib/framework/tool...
  • 15. Assert  Lerágott csont, de szerintem hasznos   Control-flow invariant, etc.  Nem egy DbC facility, de hasznos:  Internal Invariants  Control-Flow Invariants  Preconditions, Postconditions, and Class Invariants http://docs.oracle.com/javase/1.4.2/docs/guide/lang/assert.html
  • 16. Unit tesztek  Egységek (pl. modellek) tesztelésére  Tonnányi keretrendszer (JUnit/TestNG/...)  Kent Beck (XP megalkotója, Agile demigod), Erich Gamma (hasonló kaliberű úriember, pl. Eclipse JDT- ben volt benne a keze) haxolta össze egy repülőgépen a JUnit első verzióját.
  • 17. Példa public class Utils { public static int sum(int[] arr) { if (null == arr) { throw new IllegalArgumentException("arr == null"); } int sum = 0; for (int i : arr) { sum += i; } return sum; } }
  • 18. Tesztek (JUnit 4.x) import org.junit.* ; import static org.junit.Assert.* ; public class UtilsTest { @Test public void assertSumForZeroArray() { final int[] arr = new int[0]; // Given final int actual = Utils.sum(arr); // When final int expected = 0; // Then assertEquals("Sum of empty array must be zero.", expected, actual); } @Test(expected=IllegalArgumentException.class) public void assertForIllegalArgument() { Utils.sum(null); } }
  • 19. Egyéb hasznos annotációk @Ignore("John broke this yesterday") @Test(timeout=1000) @Test public void public void someMethodThatShouldRunInAMinute() { someBuggyOrUnimplementedTest() { // ... // ... } } @Before @BeforeClass public void beforeEachTest() { public void initializeStuffBeforeAnyTests() { // ... // ... } } @After @AfterClass public void afterEachTest() { public void cleanupStuffAfterAllTests() { // ... // ... } }
  • 20. Egyéb hasznos assert utasítások  assertTrue(...);  Tonnányi egyéb  assertFalse();  Ld. Assert javadoc  fail();  assertEquals(...);  assertArrayEquals(...);  assertEquals(...);  assertNotNull(...);  assertNull(...);  assertSame(...);  assertNotSame(...);  assertEquals(...);  assertThat(...); // Matcher
  • 21. Common Pitfalls  Egy teszt-egy állítás (nem feltétlen egy assert utasítás)  Teszttel is játsz egy kicsit! Az is kód, abban is annyira bízz...  Triviális tesztek!   Triviális hibakeresés  Ajánlás: tényleges kód és a tesztek külön source mappában (production kódban semmi helye, tisztességes build tooloknál ez alap)  Láthatóság: a legritkább esetben oldjuk fel tesztek miatt. Legyen ez az utolsó, amivel próbálkozunk!  Vigyázat, 2 JUnit osztály van! A másik legacy...  Randomizálás? Inkább ne...  Mutation testing  assertTrue(actual == 0) != assertEquals(expected, actual)
  • 22. IDE Integráció  Eclipse  Hozzáadás: Project jobklikk -> Properties -> Java Build Path -> Libraries -> Add Library -> JUnit -> JUnit 4 (alapból benne van)  Futtatás: Jobklikk -> Run As... -> JUnit  NetBeans  Alapból benne van egy egyszerű Java projectben.
  • 24. Mocking  Motiváció: adatbázis nincs...  DAO-s példa: van interfész, van JdbcDao implementáció, aztán meg Test1Dao implementáció...  DE! Helyette: lehet mockolni, ügyes cuccok (Néha már-már internal DSL benyomását keltő toolok)  Ebből is van egy pár...
  • 25. Mocking frameworkök – ízelítő http://code.google.com/p/jmockit/wiki/MockingToolkitComparisonMatrix
  • 26. Mocking: Példa public void testBobsLogin() { User results = new User(); String userName = "bob"; String password = "bob1234"; String passwordHash = "0340e21833f1291f673fcaab8d13"; expect(mockDao.queryUserData(userName, passwordHash)) .andReturn(results); replay(mockDao); assertTrue(service.login(userName, password)); verify(mockDao); }
  • 27. Tonnányi egyéb feature  Ellenőrzések  Hívások min/max/pontos száma  Sorrendiség  Részleges mockolás  Spy: adott függvények kiütésére  Viselkedés felvétele, visszajátszása, ellenőrzése  ...
  • 28. PowerMock  Ha elértük a korlátokat, "jó lenne..." funkciók  Támogat több platformot  Mockito/EasyMock/...  Példák:  statikus függvények mockolása  final classok mockolása  ...
  • 29. Hamcrest  Matcher library (innen a név)  "Literate programming" (Knuth, 1970)  Példával a legkönnyebb megérteni:  assertThat("Ray went to holiday", developers.getRay().countReadBooks(), equalTo(10));  assertThat(Math.sqrt(-1), is(notANumber()));  A BDD-s srácok nagyon szeretik  Kényelmi funkcionalitása van
  • 30. Design by Contract  Eiffel – Bertrand Meyer  Minden komponensnek contractja van (Nem is áll olyan messze tőlünk, ld. equals(), hashCode() Javadocját!)  Ebből is van tonnányi, 3 példa:  comment, annotációs, konfigurációs osztályos  Invariáns, elő- és utófeltételek  Assertekkel kiváltható? Nem igazán...  AspectJ-vel lehet játszani egy szintig, de...  Hol hasznos? Pl. szervleteknél ott, ahol macera a tesztelés
  • 31. Példa @Invariant("getCount() >= 0") public interface Stack<E> { int getCount(); ... @Ensure("{result}==(getCount()==0)") public boolean isEmpty(); @Require("getCount() > 0 ") @Ensure("getCount() == {old getCount()} - 1 ") void remove(); }
  • 32. Code coverage  Nagyobb projectnél könnyű elveszteni, mit mennyire teszteltünk  Megoldás: Code coverage (számtalan definíció szerint)  Reneteg tool, pl. Clover, Cobertura (generált doksik királyak)  Vannak pluginok az IDE-kben, pl. EclEmma
  • 33. Code coverage  Maximizálni érdemes, nem érdemes?  Nem biztos, hogy megéri a 100%-ra hajtani - bár láttam már ilyet (és nem is mindig megoldható, pl. BufferedReadert megfelelően használni lehetetlen)  Néha meg a 400% is kevés...  Koncentráljunk a lényeges komponensekre
  • 34. Continuous Integration rendszerek  Rengeteg tool: Hudson, Jenkins, Bamboo, ...  Mikor?  Ha sok teszt van, és nem elég a GridGain farm pl. Unit tesztek gyorsan lefutnak, de lehetnek sokan.  Integráció! pl. cm/inch  Kapható/építhető build status jelző  http://hackaday.com/2011/04/12/led-build-monitor-helps-keep-an-eye-on-your-servers/
  • 35. Sonar  Mindenféle statisztikák - a trend miatt fontos.  Összekötve a CI rendszerrel  Mutatja a tesztelésre szoruló részeket  Tonnányi projecthez példa:  http://nemo.sonarsource.org/
  • 36. Acceptance tesztek  Rengeteg tool, framework, pl. FitNesse, Specs2  Decision table egy Wikibe  Teszt, minimális kóddal  Átruházható a tesztírás a kliensre  Haha...
  • 37. Példa: FitNesse  Wiki: |eg.Division| |numerator|denominator|quotient?| |10 |2 |5 | |12.6 |3 |4.2 | |100 |4 |33 |  Kell hozzá egy minimális Java osztály, 3 adattaggal  Lesz egy nagy zöld „Teszt” gomb  Meg lehet nyomni  Példa: http://fitnesse.org/FitNesse.UserGuide.TwoMinuteExample
  • 39. BDD  Wiki:  BDD is a second-generation, outside–in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology. It describes a cycle of interactions with well-defined outputs, resulting in the delivery of working, tested software that matters.  Magyarul: értse meg a nem kóder is a teszteket 
  • 40. DSL – Scala, Specs1/2 class HelloWorldSpec extends Specification { "The 'Hello world' string" should { "contain 11 characters" in { "Hello world" must have size(11) } "start with 'Hello'" in { "Hello world" must startWith("Hello") } "end with 'world'" in { "Hello world" must endWith("world") } } } Forrás: http://etorreborre.github.com/specs2/
  • 41. DSL – Scala, Specs2 import org.specs2._ class HelloWorldSpec extends Specification { def is = "This is a specification to check the 'Hello world' string" ^ p^ "The 'Hello world' string should" ^ "contain 11 characters" ! e1^ "start with 'Hello'" ! e2^ "end with 'world'" ! e3^ end def e1 = "Hello world" must have size(11) def e2 = "Hello world" must startWith("Hello") def e3 = "Hello world" must endWith("world") }
  • 42. DSL – Groovy (Spock) @Unroll void "Ship goes to red alert only when enemy charges weapons"() { given: CommandComputer commandComputer = new CommandComputer() and: ~JUnit Theories, de egyszerűbb when: szintakszissal commandComputer.updateFromSensors(sensorReading) Forrás: http://sett.ociweb.com/sett/settFeb2012.html then: commandComputer.getAlertStatus() == expectedAlertStatus where: entityType << [EntityType.SHIP, EntityType.ANOMALY] powerReading << [PowerReading.HIGH, PowerReading.LOW] friendOrFoe << [FriendOrFoe.FOE, FriendOrFoe.UNKNOWN] powerType << [PowerType.WEAPONS, PowerType.RADIATION] direction << [Direction.TOWARD_SHIP, Direction.AWAY_FROM_SHIP] expectedAlertStatus << [AlertStatus.RED, AlertStatus.GREEN] }
  • 43. DSL – Groovy (Spock) void "red alert causes shields be raised with the correct shield frequency"() { given: EnvironmentSystem environmentSystem = Mock(EnvironmentSystem) ShieldSystem shieldSystem = Mock(ShieldSystem) CommandComputer commandComputer = new CommandComputer() commandComputer.setEnvironmentSystem(environmentSystem) commandComputer.setShieldSystem(shieldSystem) when: String result = commandComputer.execute("Red Alert") then: 1 * shieldSystem.raiseShields({int shieldFrequency -> shieldFrequency == commandComputer.getShieldFrequency() }) >> 100 result.contains("Shield Strength 100%") }
  • 44. UI Testing  Számtalan változat:  WindowsTester  Jubula (Eclipse-ben alapból van már)  FEST  Jemmy  Maveryx  ...
  • 45. Selenium (Play!) #{selenium 'Test security'} clearSession() open('/admin') assertTextPresent('Login') type('login', 'admin') type('password', '12345') clickAndWait('signin') assertText('success', 'Welcom admin!') #{/selenium}
  • 46. Selenium – Java API WebDriver driver = new FirefoxDriver(); driver.get("http://www.google.com"); WebElement element = driver.findElement(By.name("q")); element.sendKeys("Cheese!"); element.submit(); // Wait for the page to load, timeout after 10 seconds (new WebDriverWait(driver, 10)).until(new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver d) { return d.getTitle().toLowerCase().startsWith("cheese!"); } }); driver.quit();
  • 47. Egyéb hasznos toolok  FindBugs – meglepődtök majd...  PMD/CMD  Patternek, ajánlások  Copy & paste kódok kiszűrése  Ant/Maven targetek, GUI-s alkalmazás, Eclipse plugin
  • 48. Amiről nem esett szó, de jó lenne...  Stressz-teszt  JMeter http://netbeans.org/kb/docs/javaee/ecommerce/test-profile.html  Selenium IDE  Mutation testing: kipróbálod, szar, tényleg reccsen? (pl. PIT, a JUnitos srácok csinálják)  JUnit:  Theories, experimental feature-ök  Data tables  Arquillian (JBoss test framework)  Security testing:  Acuentix WebVulnerability Scanner, SQL Ninja, Tenable Nessus, ...
  • 49. Összefoglalás  Megéri? Kódot megírni ~t idő, tesztelve megírni ~3t  DE! 2-3 manuális teszt után már egyértelműen megéri a befektetés (szerintem)  Tekintve, hogy p megírás, q fenntartás, és p <<< q...
  • 50. Összefoglalás  Saját tapasztalat:  Kb. mindegy, melyik toolt használod, csak használd!  Megszünnek a napokig tartó debuggolások  Nem félsz hozzányúlni a kódhoz  Nem elfelejteni: a tesztkód írása ugyanolyan fegyelmet követel a fejlesztőtől, mint a tényleges kód írása...  Ha megszokod, nem kód többé, amihez nincs teszt (pl. R-ben is csak tesztekkel írok scriptet)  Tesztet írni fun – kielégíti az ember lelkének gonoszkodó kis részét   Jó, ha van 3 környezet: dev – test – prod
  • 51. Megjegyzések  Metrikák: nem túl hasznosak, korrelálnak a LoC-dal  Sonar: „minőségi mutatók”  Könyvajánló: Robert C. Martin: Clean Code: A Handbook of Agile Software Craftsmanship Martin J. Fowler et al.: Refactoring Improving the Design of Existing Code
  • 52. éé
  • 54. Köszönöm a figyelmet! Legéndi Richárd Olivér AITIA Szeminárium rlegendi@aitia.ai http://people.inf.elte.hu/legendi/ 2012. május 25.
  • 55. Demo  Eclipse: JUnit hozzáadása, futtatása  Eclipse: Code coverage mutogatása  Sonar: EDN project  Crisis: Mark 1 Jenkins-project  Generált Maven doksi  Code coverage