32
Unit Testing @jordi9 4 diciembre 2010

Unit Testing - GTUG

Tags:

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Unit Testing - GTUG

Unit Testing

@jordi94 diciembre 2010

Page 2: Unit Testing - GTUG

roadmapDefinición

Primer test

Excusas

Tipos de tests

<3 Mockito

Código testeable

Q & A

#bcngtug

http://bitbucket.org/jordi9/gtug-unit-testing

http://slideshare.net/giro9

Page 3: Unit Testing - GTUG

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 - GTUG

nuestro primer testframeworksxUnit family: SUnit, JUnit, NUnit, PHPUnit...Nos facilitan como escribir un test, ejecutarlo y obtener resultados.(ejemplos en JUnit)

esquema básico de un testClass Under Test (CUT, SUT, @Unit...)Precondición - Ejecución - Postcondición

postcondición...? AssertassertTrue(boolean);assertEquals(expected, actual);(...)

HamcrestassertThat(foo, is("foo")); assertThat(bar, is(not("foo"))); assertThat(list, hasSize(9)); 

Page 5: Unit Testing - GTUG

ejemplo

primer test

Page 6: Unit Testing - GTUG

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 - GTUG

tipos de test

by @mhevery

Page 8: Unit Testing - GTUG

excusas...

by @mhevery

Page 9: Unit Testing - GTUG

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 - GTUG

test con dependencias / mocks

Dependencias falsas: mocks

frameworks

fases"expect" - "replay" - "verify"

Page 11: Unit Testing - GTUG

ejemplo

<3 mockito

Page 12: Unit Testing - GTUG

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 - GTUG

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 14: Unit Testing - GTUG

ejemplo

/etc/junit

Page 15: Unit Testing - GTUG

detectar código no testeable

new's encapsulados

Coste de construcción

Estado global

API's que engañan

Page 16: Unit Testing - GTUG

new's encapsuladosclass House {  Kitchen kitchen = new Kitchen();  Bedroom bedroom;

  House() {   bedroom = new Bedroom();  }}

Page 17: Unit Testing - GTUG

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 18: Unit Testing - GTUG

new's encapsulados fixedclass House {  Kitchen kitchen;  Bedroom bedroom;

  @Inject // Guice!  House(Kitchen kitchen, Bedroom bedroom) {    this.kitchen = kitchen;    this.bedroom = bedroom;  }}

Page 19: Unit Testing - GTUG

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 20: Unit Testing - GTUG

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 21: Unit Testing - GTUG

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 22: Unit Testing - GTUG

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 23: Unit Testing - GTUG

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 24: Unit Testing - GTUG

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 25: Unit Testing - GTUG

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 org.donky.gtug.CreditCard.charge()

Page 26: Unit Testing - GTUG

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 org.donky.gtug.CreditCardProcessor.init()

Page 27: Unit Testing - GTUG

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 org.donky.gtug.OfflineQueue.start()

Page 28: Unit Testing - GTUG

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 29: Unit Testing - GTUG

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 30: Unit Testing - GTUG

muchísimas más cosas!

más frameworksDbUnitWebDriver / Selenium 2MockRunnerAndroid: ActivityInstrumentationTestCase          ActivityUnitTestCase

metodologíasTest Driven Development (<3)Acceptance Test

utilidadesTest coverage: Cobertura / CloverTestability Explorer

Page 31: Unit Testing - GTUG

gracias!

[email protected]@jordi9

Page 32: Unit Testing - GTUG

Q & A

[email protected]@jordi9