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”
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() { // ...
// ... }
}
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...
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]
}
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();
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