Unit Testing - Trovit
-
Upload
jordi-gerona -
Category
Documents
-
view
660 -
download
1
description
Transcript of Unit Testing - Trovit
![Page 1: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/1.jpg)
Unit Testing
@jordi94 noviembre 2011
![Page 2: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/2.jpg)
roadmapDefinición
Primer test
Excusas
Tipos de tests
<3 Mockito
Código testeable
Q & A
#trovitrocks
http://bitbucket.org/jordi9/gtug-unit-testing
http://slideshare.net/giro9
![Page 3: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/3.jpg)
definición
Código (método) que ejecuta un otro código para comprobar su validez.
... todos hemos escrito unit tests (o algo parecido)
característicasAutomático y repetibleFácil de implementar.Cualquiera puede ejecutarlo "apretando un botón"Debe ser rápido (<1ms)
![Page 4: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/4.jpg)
nuestro primer testframeworksxUnit family: SUnit, JUnit, NUnit, PHPUnit...Nos facilitan como escribir un test, ejecutarlo y obtener resultados.
esquema básico de un testSystem Under Test (SUT)Precondición - Ejecución - Postcondición setup > excercise > verify > teardown
postcondición...? AssertassertTrue(boolean);assertEquals(expected, actual);(...)
HamcrestassertThat(foo, is("foo")); assertThat(bar, is(not("foo"))); assertThat(list, hasSize(9));
![Page 5: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/5.jpg)
ejemplo
primer test
![Page 6: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/6.jpg)
test con junit
public class StringsTest { @Test public void stripAllHTMLForAGivenText() { String html = "<a>Link</a>"; assertThat(Strings.stripHTML(html), is("Link")); } }
public class Strings {
public static String stripHTML(String input) { return input.replaceAll("</?+(\\b)[ˆ<>]++>", ""); } }
unit test
![Page 7: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/7.jpg)
tipos de test
by @mhevery
![Page 8: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/8.jpg)
excusas...
by @mhevery
![Page 9: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/9.jpg)
unit test...?
// Class under test CreditCardProcessor creditCardProcessor;
@Testpublic void chargeCreditCard() { creditCardProcessor = new CreditCardProcessor(); CreditCard c = new CreditCard("9999 0000 7777", 5, 2009); creditCardProcessor.charge(c, 30.0); assertThat(creditCardProcessor.balance(c), is(-30.0));}
public CreditCardProcessor() {}
Mi tarjeta tenía 30 Euros menos!
![Page 10: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/10.jpg)
test con dependencias / mocks
Dependencias falsas: mocks
frameworks
fases"expect" - "replay" - "verify"
![Page 11: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/11.jpg)
ejemplo
<3 mockito
![Page 12: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/12.jpg)
preparando un test@Before @AfterSe ejecutan por cada test unitario
public class DatabaseTest { @Before public void prepareFakeDatabase() {}
@After public void cleanupFakeDatabase() {}}
@BeforeClass @AfterClassSe ejecutan una vez por un conjunto de test
public class DatabaseTest { @BeforeClass public static void prepareRealDatabase() {} @AfterClass public static void cleanupRealDatabase() {}}
![Page 13: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/13.jpg)
fixtures preconditions
Transient fresh fixturesCada test construye su fixture cada vez y para el solo. Muy fácil de mantener -- Tests totalmente independientes Sirve como Test as Documentation + Minimal Fixture No teardown -- Implicito
Persistent fresh fixturesTests de integración Caso claro: Tests con base de datos Teardown
Shared fixturesReutilizamos los fixture entre varios tests pero... Rompemos la regla de oro: Keep Tests Independent... =\ Problemas infinitos: Erratic Tests, Obscure Test http://goo.gl/oxpca | http://goo.gl/22Q19
Difícil de mantener: Fragile Fixture http://goo.gl/TDUw0
![Page 14: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/14.jpg)
más opciones junittesteando excepciones@Test(expected=IllegalArgumentException.class)public void emptyInputShouldRaiseAnException() { Strings.stripHTML("");}
tests con timeout@Test(timeout=1000)public void timeoutFirst() { Strings.veryLongMethod("foo");}
ignorar un test@Ignore("Some very good reason")@Test(timeout=1000)public void timeoutFirst() { Strings.veryLongMethod("foo");}
![Page 15: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/15.jpg)
ejemplo
/etc/junit
![Page 16: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/16.jpg)
detectar código no testeable
new's encapsulados
Coste de construcción
Estado global
API's que engañan
![Page 17: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/17.jpg)
new's encapsuladosclass House { Kitchen kitchen = new Kitchen(); Bedroom bedroom;
House() { bedroom = new Bedroom(); }}
![Page 18: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/18.jpg)
new's encapsuladosclass House { Kitchen kitchen = new Kitchen(); Bedroom bedroom;
House() { bedroom = new Bedroom(); }}
class HouseTest {
@Test public void thisIsReallyHard() { House house = new House(); // Oops... y si quiero utilizar otra cocina u otra // habitación? }}
![Page 19: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/19.jpg)
new's encapsulados fixedclass House { Kitchen kitchen; Bedroom bedroom;
@Inject // Guice! House(Kitchen kitchen, Bedroom bedroom) { this.kitchen = kitchen; this.bedroom = bedroom; }}
![Page 20: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/20.jpg)
new's encapsulados fixedclass House { Kitchen kitchen; Bedroom bedroom;
@Inject // Guice! House(Kitchen kitchen, Bedroom bedroom) { this.kitchen = kitchen; this.bedroom = bedroom; }}
class HouseTest {
@Test public void thisIsCoolAndFlexible() { Kitchen kitchen = new FooKitchen(); Bedroom bedroom = new InexpensiveBedroom();
House house = new House(kitchen, bedroom); // yay! }}
![Page 21: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/21.jpg)
Coste de construcción
class Car { Engine engine; Car(File file) { String model = readEngineModel(file); // expensive method engine = new EngineFactory().create(model); }}
Para instanciar un objeto: Tienes que navegar por todo lo que se haga en la constructora. No puedes sobrescribirla.
![Page 22: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/22.jpg)
Coste de construcción
class Car { Engine engine; Car(File file) { String model = readEngineModel(file); // expensive method engine = new EngineFactory().create(model); }}
class CarTest { public void noSeamForFakeEngine() { // Aggh! Ficheros en los unit tests... File file = new File("engine.config"); Car car = new Car(file); // Quiero utilizar otro motor pero no puedo por culpa // de la fábrica... }}
Para instanciar un objeto: Tienes que navegar por todo lo que se haga en la constructora. No puedes sobrescribirla.
![Page 23: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/23.jpg)
Coste de construcciónclass Car { Engine engine; Car(Engine engine) { this.engine = engine; }}
@Provides // más Guice!Engine providesEngine(EngineFactory engineFactory, @EngineModel String model) { return engineFactory.create(model);}
![Page 24: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/24.jpg)
Coste de construcciónclass Car { Engine engine; Car(Engine engine) { this.engine = engine; }}
@Provides // más Guice!Engine providesEngine(EngineFactory engineFactory, @EngineModel String model) { return engineFactory.create(model);}
@Testpublic void nowWeHaveACleanDesign() { Engine fakeEngine = new FakeEngine(); Car car = new Car(fakeEngine);}
Hacer el mínimo trabajo posible en la constructora
![Page 25: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/25.jpg)
Estado globalRepetir el mismo proceso y obtener un resultado diferente... ugh!
síntomasOrden de los tests importa (prohibido!)No se pueden ejecutar los tests en paralelo
ejemplosEn la propia JVM tenemos malos ejemplos: System.currentTime(); new Date(); Math.random()
Testear el código anterior es muy difícil.
![Page 26: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/26.jpg)
APIs engañosasDependencias ocultas... recuperemos el ejemplo de antes
@Testpublic void chargeCreditCard() { CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009); cc.charge(30.0);}
java.lang.NullPointerExpection at com.trovit.unittesting.CreditCard.charge()
![Page 27: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/27.jpg)
APIs engañosas@Testpublic void chargeCreditCard() { CreditCardProcessor.init(); CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009); cc.charge(30.0);}
java.lang.NullPointerExpection at com.trovit.unittesting.CreditCardProcessor.init()
![Page 28: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/28.jpg)
APIs engañosas@Testpublic void chargeCreditCard() { OfflineQueue.start(); CreditCardProcessor.init(); CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009); cc.charge(30.0);}
java.lang.NullPointerExpection at com.trovit.unittesting.OfflineQueue.start()
![Page 29: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/29.jpg)
APIs engañosas@Testpublic void chargeCreditCard() { Database.connect(...); OfflineQueue.start(); CreditCardProcessor.init(); CreditCard cc = new CreditCard("9999 0000 7777", 5, 2009); cc.charge(30.0);}
La API de CreditCard nos engaña: No expone sus dependencias de manera clara. Pretende no necesitar la CreditCardProcessor pero lo hace. Aun pierdo 30 Euros!
Si tu código depende del orden en que se inician los Singletons... está documentado en alguna parte? Quien no se ha encontrado esto nunca? ;)
La solución es Dependency Injection: Te fuerza el orden correcto en tiempo de compilación.
![Page 30: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/30.jpg)
una solución mejor@Testpublic void chargeCreditCard() { db = new Database(...); queue = new OfflineQueue(db); ccProc = new CreditCardProcessor(queue); CreditCard cc = new CreditCard(ccProc, "9999 0000 7777"); cc.charge(30.0);}
![Page 31: Unit Testing - Trovit](https://reader035.fdocuments.net/reader035/viewer/2022062616/54b4fb6e4a795980778b45d7/html5/thumbnails/31.jpg)
muchísimas más cosas!
más frameworksDbUnitWebDriver / Selenium 2MockRunnerAndroid: ActivityInstrumentationTestCase ActivityUnitTestCase
metodologíasTest Driven Development (<3)Acceptance TestContinous Integration / Jenkins
utilidadesTest coverage: Cobertura / CloverTestability Explorer