77
Proves de software (en Java amb JUnit) Juan Manuel Gimeno Illa [email protected]

Proves de Software (en Java amb JUnit)

Embed Size (px)

DESCRIPTION

Apunts de proves unitàries en Java usant JUnit.

Citation preview

Proves de software(en Java amb JUnit)

Juan Manuel Gimeno Illa

[email protected]

2

Índex

● Què i per què dels tests unitaris● Com? ● El framework JUnit (3.x)● Proves en aïllament● Tipus de proves dins del cicle de vida

3

Necessitat dels tests unitaris

● Quan programem necessitem saber si el que hem construït realment funciona

● Per tant el que hem de fer és executar els nostres “tests d'acceptació”

● Normalment ho fem però de forma informal:● No són automàtics (provem a mà)● No els repetim (problemes de regressió)● No són focalitzats (provem moltes coses de cop)

4

Definició de test unitari

● Un test unitari comprova que un mètode● accepta un rang de valor esperats ● i que retorna els valors esperats per cada valor

provat.

● Per tant el que volem és provar el mètode a través de la seva especificació:● Si li passem el valor x retornarà el valor correcte y?● Si li passem el valor z llençarà l'excepció prefixada?

5

Fent tests manualment

● Suposem que volem testejar la següent classe:

public class Calculator {

public double add(double number 1, double number2) {

return number1 + number 2;

}

}

6

Fent tests manualment

● Com podem provar aquesta classe?● Fem un programa que demani dos nombres i

comprovem que el resultat és correcte?● Quants nombres entrarem?● Si trobem un error i modifiquem el programa,

recordarem els que haviem provat abans?

● La idea és fer un programa que faci això automàticament de manera que es pugui repetir tantes vegaden com calgui!!

7

Programant una classe de provapublic class Test Calculator {

public static void main (String[] args) {

Calculator calculator = new Calculator();

double result = calculator.add(10, 50);

If (result != 60) {

System.out.println(“Bad result: “ + result);

}

}

}

● S'ha d'estar pendent de la sortida per si hi ha errors

● A més la forma convencional d'assenyalar errors en Java són les excepcions

8

Millorant la classe de provapublic class TestCalculator {

private int nbErrors = 0;public void testAdd() {

Calculator calculator = new Calculator();double result = calculator.add(10, 50);if (result != 60) {

throw new RuntimeException(“Bad result: “ + result);}

}public static void main(String[] args) {

TestCalculator test = new TestCalculator();try {

test.testAdd();} catch (Throwable e) {

test.nbErrors++;e.printStackTrace();

}if (test.nbErrors > 0) {

throw new RuntimeException(“There were “ + test.nbErrors + “ error(s)”);}

}}

Cada prova estàimplementada en

un mètode

Fàcil afegirnoves proves

9

Frameworks de proves unitàries

● Un framework per p.u. ha de seguir un conjunt de “bones pràctiques”● Cada test ha d'executar-se de forma independent a

tots els altres● Els errors s'han de detectar i mostrar test a test● Ha de ser fàcil poder seleccionar quins tests

s'executaran

● El framework JUnit proveeix de totes aquestes facilitats (i més)

10

El Framework JUnit

● Proveeix diversos front-ends per mostrar els resultats dels tests (línia de comanda, awt, swing, …)

● Classloaders diferents per a cada test per evitar “efectes laterals”

● Mètodes estàndard per inicialitzar i alliberar recursos (setUp and tearDown)

● Varietat d'assercions per a comprovar els resultats de les proves

● Integració amb IDEs, ant, maven, ....

11

La prova usant JUnit

● javac -cp ../junit3.8.2/junit.jar *.java

● java -cp .:../junit3.8.2/junit.jar↳junit.swingui.TestRunner TestCalculator

import junit.framework.TestCase

public class TestCalculator extends TestCase {

public void testAdd() {

Calculator calculator = new Calculator();

double result = calculator.add(10, 50);

assertEquals(60, result, 0);

}

}

12

Nomenclatura de JUnit

● Test case: Classe que estén TestCase i que conté una o més proves representades pels mètodes testXXX. S'usa per agrupar proves que exerciten comportaments comuns.

● TestSuite: Agrupació de proves que estan relacionades.

● TestRunner: Llençador de grups de proves. Es prové de la classe BaseTestRunner.

TestCase Test Suite BaseTestRunner TestResult+ + =

13

Interfícies i classes de JUnit

● Assert: Conté mètodes que no fan res si la comprovació és exitosa, i llencen una excepció quan falla.

● TestResult: Recolecta els errors i fallides que es produeixen a l'executar les proves.

● Test: Un test es pot executar i rep un TestResult.

● TestListener: Rep notificacions dels events que succeeixen durant una prova (p.e. la prova comença o acaba, s'ha produït un error, etc.)

14

Interfícies i classes de JUnit (2)

● TestCase: Defineix un entorn (o fixture) que pot usar-se per executar múltiples tests.

● TestSuite: executa una col·lecció de tests, que poden incloure també altres TestSuites.

● BaseTestRunner: superclasse de tots els llençadors de tests.

15

La interfície Test

● La interfície que implementen tant la classe TestCase com la TestSuite s'anomena Test i conté el següent:

package junit.framework;

public interface Test {public abstract int countTestCases();public abstract void run(TestResult result);

}

16

Diagrama de classes

17

Creant una TestSuite

● Una TestSuite serveix per a que un TestRunner executi conjuntament diversos Tests relacionats

● Però no es vol complicar l'execució de TestCases individualment

● Solució: TestRunner crea una TestSuite de forma automàtica a partir d'un TestCase

● (Més endavant veurem que Test, TestSuite i TestCase són un exemple de patró Composite)

18

La TestSuite “automàtica”

● Escaneja la classe de test per mètodes que comencin per “test”

● Crea una instància de TestCase per a cadascun d'aquests mètodes

● El nom del mètode és passat al constructor per identificar cada instància● Aquest constructor amb nom era obligatori abans

de JUnit 3.8. Ara només cal si usat explícitament.

● La TestSuite es crea dins del mètode públic i estàtic suite()

19

suite() per TestCalculator

public static Test suite() {return new TestSuite(TestCalculator.class);

}

● El mètode estatic que es crearia és equivalent a:

● Que és equivalent a:

public static Test suite() {TestSuite suite = new TestSuite();suite.addTest(new TestCalculator(“testAdd”));return suite;

}

20

La típica classe TestAll

import junit.framework.Test;import junit.framework.TestSuite;

public class TestAll {public static Test suite() {

TestSuite suite = new TestSuite(“Tots els tests”);suite.addTestSuite(TestCalculator.class);suite.addTestSuite(TestGenerator.suite());return suite;

}}

21

Recollint resultats amb TestResult

● Una instància de TestResult recull informació sobre si els tests són exitosos o fallen.

● P.e. si la línia assertEquals(60, result, 0) falla, es crea una instància de TestFailure i es guarda a TestResult

● TestRunner usa TestResult per informar de com ha anat l'execució dels tests:● si no hi ha cap TestFailure a TestResult, green bar● si n'hi ha, s'indica el nombre d'errors i es mostra un

volcat de la traça de la pila

22

Fallides i Errors

● JUnit distingeix entre:● fallida: es 'normal' que es produeixin per exemple

degut a canvis en el codi.● error: condició no esperada per un test i que no

s'hauria de produir mai.● Quan es produeix una fallida:

● s'arregla el codi per arreglar la situació● Quan es produeix un error:

● comprovar l'entorn (configuració, xarxa, bbdd, ...)● comprovar el test● comprovar el codi

23

Fallida

24

Error

25

Observant execució amb TestListener

● La interfície TestListener permet definir objectes que accedeixin al TestResult per a informar sobre el resultat d'un test.

● Per exemple, els diferents TestRunners implementen aquesta interfície

● Es poden enregistrar tants TestsListeners com es vulgui per a fer el que es necessiti amb el TestResult.

26

Interfície TestListener

public interface TestListener {

// Cridat per notificar que s'ha produït un errorvoid addError(Test test, Throwable t);

// Cridat per notificar que s'ha produït una fallidavoid addFailure(Test test, AssertionFailedError e);

// Cridat per notificar la fi d'execució d'un testvoid endTest(Test test);

// Cridat per notificar l'inici d'execució d'un testvoid startTest(Test test);

}

27

Treballant amb TestCase

● Recordem que TestRunner executa una TestSuite que conté un o més TestCases (o d'altres TestSuites)

● El framework conté varis TestRunners● El framework crea una TestSuite per defecte● Per tant, la única classe que és absolutament

necessari programar és TestCase

28

Manegant recursos dins d'un TestCase

● Alguns tests requereixen recursos per funcionar (p.e. una connexió amb la BBDD)

● Varis tests d'un mateix TestCase poden necessitar aquests mateixos recursos

● Replicar el codi de creació i configuració d'aquests recursos en cada test no té sentit

● Fixture (accessori): el conjunt de recursos (o dades) comuns que es necessiten per executar un o més tests.

29

Execució dels mètodes testXXX

● Una fixture és creada i destruïda pels mètodes setUp i tearDown de TestCase.

● El TestCase crida de forma automática setUp (tearDown) abans (després) d'executar cada mètode de test.

● Una de les raons de posar varis mètodes de test a un TestCase és compartir la fixture.

30

El supertipus Assert

● Classe d'utilitat que conté mètodes per avaluar condicions

● Tots ells llencen AssertionFailedError quan fallen i tenen vàries versions (p.e. AssertEquals en té 20)

● Mirant el javadoc un veuen 38 mètodes però en el fons “només” són 8 mètodes:

assertTrue assertNull

assertFalse assertSame

assertEquals assertNotSame

assertNotNull fail

31

Els altres mètodes de TestCase

public abstract class TestCase extends Assert implements Test {

public TestCase() {...}public TestCase(String name) {...}public int countTestCases() {...} protected TestResult createTestResult() {...}public TestResult run() {...}public void run(TestResult result) {...}public void runBare() throws Throwable {...}protected void runTest() throws Throwable {...}protected void setUp() throws Exception {...}protected void tearDown() throws Exception {...}public String toString() {...}public String getName() {...}public String setName(String name) {...}

}

32

Regla d'or de l'escriptura de tests

● Cada test unitari ha d'executar-se de manera independent de tots els altres tests unitaris● han de poder executar-se en qualsevol ordre● sense dependre d'efectes laterals produïts pels

tests previs

● Problemes que produeixen tests dependents:● portabilitat (ja que JUnit usa reflexió)● mantenibilitat● llegibilitat

33

Recordem TestCalculator

import junit.framework.TestCase

public class TestCalculator extends TestCase {

public void testAdd() {

Calculator calculator = new Calculator();

double result = calculator.add(10, 50);

assertEquals(60, result, 0);

}

}

● El que farem es tracejar l'execució de la classe TestCalculator, mitjançant varis diagrames de seqüència

● Recordem el codi de la classe:

34

Tracejant TestCalculator

● Quan s'executa

java junit.swingui.TestRunner TestCalculator● El framework JUnit fa el següent:

● crea una TestSuite● crea un TestResult● executa els mètodes de test (en aquest cas

testAdd)

35

Creant una TestSuite (explícitament)

● Si TestCase conté un mètode suite explícit:

public static Test suite() {TestSuite suite = new TestSuite();suite.addTest(new TestCalculator(“testAdd”));return suite;

}

36

Creant una TestSuite (implícitament)

● Si no hi ha mètode suite, via instrospecció, es crea la TestSuite buscant mètodes que contenen mètodes testXXX.

37

Creant un TestResult

38

Creant un TestResult (cont.)

(1)TestRunner instancia el TestResult

(2)TestRunner s'enregistra com observador del TestResult

(3)TestRunner crida al mètode run de la TestSuite el qual crida al mètode run del TestCase i aquest crida al mètode run del TestResult

(4)El TestResult notifica que comença a executar un test

(5)TestResult executa el test amb el mètode runBare

39

Executant els mètodes de test

40

Executant els mètodes de test (cont.)

(1)runBare és el responsable de cridar a setUp, al mètode de test (testAdd) i a tearDown

(2)en cas de produir-se un una fallida (durant l'execució de qualsevol d'aquests tres mètodes), aquesta es notifica a TestRunner.

(3)en cas d'error inesperat, també es notifica

(4)finalment, es notifica que s'ha acabat l'execució del test.

41

Exemple de classe de proves

public class OrderStateTester extends TestCase {private static final String TALISKER = "Talisker";private static final String HIGHLAND_PARK = "Highland Park";private Warehouse warehouse = new WarehouseImpl();

protected void setUp() throws Exception {warehouse.add(TALISKER, 50);warehouse.add(HIGHLAND_PARK, 25);

}

public void testOrderIsFilledIfEnoughInWarehouse() {Order order = new Order(TALISKER, 50);order.fill(warehouse);assertTrue(order.isFilled());assertEquals(0, warehouse.getInventory(TALISKER));

}

public void testOrderDoesNotRemoveIfNotEnough() {Order order = new Order(TALISKER, 51);order.fill(warehouse);assertFalse(order.isFilled());assertEquals(50, warehouse.getInventory(TALISKER));

}}

42

Estructura típica dels tests

● Un test sol tenir quatre fases:● inicialització: parcialment es fa a setUp

(warehouse) i a cada test (order)● execució: es fa que l'objecte invoqui el mètode que

es vol provar (order.fill)● comprovació: es comprova que el resultat del

mètode és l'esperat (asserts)● neteja: s'alliberen recursos (en aquest cas es fa de

forma implícita i ho farà el recol·lector de deixalles)

43

Nomenclatura

● System Under Test (SUT): objecte que s'està provant.En el nostre cas es tracta de l'objecte order

● Col·laborador(s): objectes que es necessiten per tal de poder provar el SUT.En el nostre cas es tracta de warehouse● ho necessitem doncs order.fill crida a mètodes de

warehouse● també ho necessitem per a verificar que order.fill

canvia correctament l'estat de warehouse

44

Verificació de l'estat

● És una de les formes de verificar que l'execució ha estat la correcta.

● Consisteix en verificar que tant l'estat del SUT com dels objectes col·laboradors són els correctes després d'executar el mètode que es vol provar.

● (Posteriorment veurem que els mocks permeten un altre estil de verificació).

45

Proves en aïllament

● Moltes vegades el codi que volem testejar depèn d'altres classes que depenen de l'entorn:● usen JDBC per accedir a una base de dades● utilitzen els serveis d'un contenidor J2EE● accedeixen al sistema de fitxers● connecten amb altres recursos via HTTP, SOA, ...

● Per “simular” aquests serveis externs podem usarem TestDoubles (objectes substitutius)

46

Tipus de TestDoubles

● Hi ha varis tipus de substituts:● Dummy objects que només es passen per satisfer

paràmetres● Fake objects que tenen implementacions no

vàlides per producció● Stubs que tenen respostes prefixades a les crides

que es fan al test● Mocks que tenen expectatives pre-programades

que formen una especificació de les crides que esperen rebre durant el test

47

Stubs/Fakes

● Com des del punt de vista del test es comporten igual, els analitzarem conjuntament (i farem servir només la denominació Stub)

● La intenció és substituir un comportament complex amb un de més simple que permeti el testeig independent de part del codi.● no replicant tota la funcionalitat● amb una implementació simple no vàlida per

producció (p.e. bbdd en memòria)● respostes prefixades

48

Utilitat dels stubs

● Els stubs donen confiança en el sistema sota proves ja que aquest no es modifica

● Quan pot ser útil usar stubs:● no es pot modificar un sistema existent perquè és

molt complex i fràgil● per proves “gruixudes” com integració de diversos

subsistemes

49

Exemple de Stub

public interface MailService {public void send (Message msg);

}

public class MailServiceStub implements MailService {private List<Message> messages = new ArrayList<Message>();public void send (Message msg) {

messages.add(msg);}public int numberSent() {

return messages.size();}

} class OrderStateTester ....

public void testOrderSendsMailIfUnfilled() {Order order = new Order(TALISKER, 51);MailServiceStub mailer = new MailServiceStub();order.setMailer(mailer);order.fill(warehouse);assertEquals(1, mailer.numberSent());

}}

Comprovem que s'ha enviat el

correu

Només implementemla funcionalitat que

necessitem

50

Inconvenients dels stubs

● Els stubs poden ser difícils d'implementar ja que s'ha de replicar la lògica de funcionament del sistema substituït

● Poden ser difícils de mantenir per la seva complexitat

● Un stub no s'adiu amb unit testing de “grau fi”● Cada situació (element a substituir per un stub)

necessita d'una estratègia particular.

51

Mocks

● Són objectes substitutius que es diferencien dels anteriors en la forma que es verifiquen:● stubs/fakes: verificació d'estat, és a dir, al final del

test comprovem que l'estat de l'objecte● mocks: verificació de comportament

● Existeixen biblioteques addicionals que simplifiquen la seva creació: jMocK, EasyMock, Mockito, etc.

52

L'exemple usant jMock1

public class OrderInteractionTester extends MockObjectTestCase {

  private static final String TALISKER = "Talisker";

  public void testFillingRemovesInventoryIfInStock() {    //setup - data    Order order = new Order(TALISKER, 50);    Mock warehouseMock = new Mock(Warehouse.class);        //setup - expectations    warehouseMock.expects(once()).method("hasInventory")      .with(eq(TALISKER),eq(50))      .will(returnValue(true));    warehouseMock.expects(once()).method("remove")      .with(eq(TALISKER), eq(50))      .after("hasInventory");

    //exercise    order.fill((Warehouse) warehouseMock.proxy());        //verify    warehouseMock.verify();    assertTrue(order.isFilled());  } .....

53

L'exemple usant jMock1 (cont.)

public void testFillingDoesNotRemoveIfNotEnoughInStock(){

    Order order = new Order(TALISKER, 51);        Mock warehouse = mock(Warehouse.class);          warehouse.expects(once()).method("hasInventory")      .withAnyArguments()      .will(returnValue(false));

    order.fill((Warehouse) warehouse.proxy());

    assertFalse(order.isFilled());}

.....

● Crear el mock usant el mètode mock fa que no calgui verificar-lo explícitament al final del test

● Posem withAnyArguments doncs ja hem verificat abans que la crida es fa amb els arguments correctes i així el test és més robust

54

L'exemple usant jMock2

public class OrderInteractionTester extends MockObjectTestCase {

private static final String TALISKER = "Talisker";

public void testFillingRemovesInventoryIfInStock() {//setup - dataOrder order = new Order(TALISKER, 50);Warehouse warehouseMock = mock(Warehouse.class);final Sequence seq = sequence(“seq”);

    //setup – expectationschecking(new Expectations() {{

oneOf(warehouseMock).hasInventory(50);inSequence(seq);will(returnValue(true));

oneOf(warehouseMock).remove(50); inSequence(seq);

}});

    //exercise    order.fill(warehouseMock);        //verify    assertTrue(order.isFilled());  } .....

55

L'exemple usant jMock2 (cont.)

public void testFillingDoesNotRemoveIfNotEnoughInStock(){

Order order = new Order(TALISKER, 51);    Warehouse warehouseMock = mock(Warehouse.class);

checking(new Expectations() {{oneOf(warehouseMock).hasInventory(with(any(int.class)));

will(returnValue(false));}});

order.fill(warehouseMock);

assertFalse(order.isFilled());}

.....

● jMock2 requereix de Java 5

● Requereix també les extensions Hamcrest de JUnit

● Un dels objectius és més seguretat dels tipus

56

L'exemple usant EasyMock

public class OrderEasyTester extends TestCase {  private static final String TALISKER = "Talisker";    private MockControl warehouseControl;  private Warehouse warehouseMock;    public void setUp() {    warehouseControl = MockControl.createControl(Warehouse.class);    warehouseMock = (Warehouse) warehouseControl.getMock();      }

  public void testFillingRemovesInventoryIfInStock() {    //setup - data    Order order = new Order(TALISKER, 50);        //setup - expectations    warehouseMock.hasInventory(TALISKER, 50);    warehouseControl.setReturnValue(true);    warehouseMock.remove(TALISKER, 50);    warehouseControl.replay();

    //exercise    order.fill(warehouseMock);        //verify    warehouseControl.verify();    assertTrue(order.isFilled());  }

57

L'exemple usant EasyMock (cont.)

public void testFillingDoesNotRemoveIfNotEnoughInStock() {    Order order = new Order(TALISKER, 51);   

    warehouseMock.hasInventory(TALISKER, 51);    warehouseControl.setReturnValue(false);    warehouseControl.replay();

    order.fill((Warehouse) warehouseMock);

    assertFalse(order.isFilled());    warehouseControl.verify();  }

● Fa servir la metàfora de la “gravadora”● el mock segueix la interfície del col·laborador que

volem substituir● el control permet indicar coses com el valor de retorn● una vegada indicat replay() sobre el control, l'objecte

mock es comportarà de la forma gravada

58

Diferències amb les proves clàssiques

● La fase d'inicialització:● la inicialització de les dades és igual però l'únic

objecte “normal” que es crea és el SUT ja que els col·laboradors són mocks.

● la segona part crea expectatives en el mocks, que són els mètodes que s'han de cridar quan es posa en marxa la funcionalitat en el SUT

● La fase de verificació també té dues parts● en una es comprova l'estat del SUT (com abans)● es verifica que les expectatives sobre els mocks

s'han complert

59

Verificació del comportament

● Fixeu-vos que sobre el mock no fem cap verificació del seu estat.

● La única cosa que es comprova és si el SUT ha invocat els mètodes adequats.

● És a dir, el que hem verificat és què s'hagi dut a terme la col·laboració adequada entre ells.

● Fixeu-vos que podem fer proves amb col·laboradors no implementats i que els mocks ens proporciones especificacions del comportament que han de tenir.

60

Comparant Stubs i Mocks

public interface MailService {public void send (Message msg);

}

public class MailServiceStub implements MailService {private List<Message> messages = new ArrayList<Message>();public void send (Message msg) {

messages.add(msg);}public int numberSent() {

return messages.size();}

} class OrderStateTester extends TestCase {

public void testOrderSendsMailIfUnfilled() {Order order = new Order(TALISKER, 51);MailServiceStub mailer = new MailServiceStub();order.setMailer(mailer);order.fill(warehouse);assertEquals(1, mailer.numberSent());

}}

61

Comparant Stubs i Mocks (cont.)

class OrderInteractionTester extends MockObjectTestCase {

public void testOrderSendsMailIfUnfilled() {

Warehouse warehouseMock = mock(Warehouse.class);MailService mailerMock = mock(MailService.class);

Order order = new Order(TALISKER, 51);    order.setMailer(mailerMock);

checking(new Expectations() {{oneOf(mailerMock).send();oneOf(warehouseMock).hasInventory(with(any(int.class)));

will(returnValue(false);}});

order.fill(warehouseMock);  }}

62

Millors pràctiques: què provar?

● Cal focalitzar-se en les coses que es poden trencar

● Els tests han d'executar-se “en silenci”● no imprimir als tests● usar assercions i excepcions

● Què no cal provar?● mètodes get/set● el bon funcionament del compilador

63

Millors pràctiques: TDD

● TDD: Test Driven Development● Escriure primer el test i després el codi que el

fa passar:

● Potser TDD és massa extrem● però és convenient crear els tests en paral·lel amb

el codi i no com un afegit posterior

TDD = Test + Code + Refactor

64

Millors pràctiques: mètodes que llencen excepcions

public class TestDefaultController extends TestCase {[...]public void testGetHandlerNotDefined() {

TestRequest request = new TestRequest(“testNotDefined”);try {

controller.getHandler(request);fail(“An exception should be raised if the requested “

+ “handler has not been registered”);} catch (RuntimeException expected) {

assertTrue(true);}

}}

65

Millors pràctiques: crear tests pels “bugs” trobats

● Malgrat els nostres esforços sempre es troben “bugs” en els nostres programes

● Quan això passa el que hem de fer és escriure un test que el manifesta● òbviament aquest test és necessari ja que el “bug”

ha escapat els nostres mecanismes de detecció● (penseu en els tests com un sedàs que no hauria

de deixar passar els errors)

● Ara ja podem arreglar el codi per a que no es produeixi● i el test assegura que no es reprodueixi

66

Millors pràctiques: dissenyar codi testejable

● Separar interfícies de les classes que les implementen● podem substituir les implementacions al testejar● podem usar mocks, stubs, etc.

● No crear objectes que són dependències dins de les classes● new només s'hauria d'usar en classes factoria● la idea és que aquests objectes creats amb new no

són substituïbles● o bé usar “injecció de dependències”

67

Els diferents tipus de proves dins del cicle de vida

● unitàries● d'integració● funcionals● estrès/càrrega● acceptació

68

Proves d'integració

● Una vegada se sap que les unitats funcionen correctament de forma independent (tests unitaris) cal veure què passa quan interactuen entre sí.

● Podem parlar d'intergració a varis nivells:● com interactuen els objectes● com interactuen els serveis (EJBs, BBDD, etc.)● com interactuen els subsistemes

● Idealment s'haurien de definir abans que es codifiquin les diverses unitats

69

Proves funcionals

● Provar les interaccions entre els diferents objectes és essencial però, el resultat esperat de l'aplicació serà el que volem?

● Les proves funcionals verifiquen el comportament a nivell dels casos d'ús definits a l'especificació.

● Si tenim l'aplicació separada en capes fariem proves a nivell dels missatges de sistema ja que aquests encapsulen tota la funcionalitat de l'aplicació.

70

Proves d'estrès i càrrega

● És important tenir una aplicació que funciona, però com es comportarà quan la utilitzin molts usuaris simultàniament?

● Normalment es fan amb software especialitzat (p.e. JMeter) que envia peticions i mira quantes son servides.

● Un altre tipus d'anàlisi es pot fer dins de l'entorn de desenvolupament usant un profiler per cercar colls d'ampolla a l'aplicació.

● També hi ha una extensió de JUnit anomenada JUnitPerf per fer proves de rendiment

71

Proves d'acceptació

● És important que el rendiment sigui el correcte però el que realment importa és: l'aplicació satisfà les necessitats del client?

● Aquests tests són realitzats pel client (o per algú que el representa).

● Aquests tests involucren també aspectes més subjectius com facilitat d'ús, d'aprenentatge, etc, etc.

72

Abast dels tests unitaris

● Encara que JUnit està específicament dissenyat per a realitzar proves unitàries, també podem escriure amb ell d'altres tipus de tests.

● Alguns consideren “unitari” tots aquests tipus de tests i distingeixen entre● tests unitaris lògics● tests unitaris d'integració● tests unitaris funcionals

73

Cicle de vida

● Recordeu que estem en un context d'un cicle de vida iteratiu i incrementar (Procés Unificat)

● Per tant, l'activitat de proves es fa a totes les iteracions i fem tots els tipus de tests per a tots els increments

● L'activitat de test (a qualsevol nivell) mai no es pot deixar pel final, just abans de fer el lliurament al client

74

Coses que no hem vist

● Integració amb altres eines com ant, maven, etc.

● Generadors d'informes: JUnitReport● Test dins de contenidors: Cactus● Anàlisi cobertura: Clover● .....

75

Bibliografia

● V.Massol, T.Husted. JUnit in Action. Manning (2004).

● A.Hunt, D.Thomas. Pragmatic Unit Testing. The Pragmatic Programmers (2003)

● M.Fowler. Mocks aren't stubs. (Darrera modificació 2-I-2007)

● Sang Shin, Unit Testing with JUnit Testing framework. (Darrera modificació 25-V-2008).

● D.Bolaños, A.Sierra, M.I.Alarcón. Pruebas de Software y JUnit. Pearson (2008)

● Miško Hevery, The Testability Explorer Blog

● Paulo Caroli, Using JMock with Test Driven Development

76

Projectes

● http://www.junit.org/● http://www.jmock.org/● http://easymock.org/● http://mockito.org/● http://code.google.com/p/hamcrest/

77

Aquesta obra està subjecta a una llicència Reconeixement-Compartir Igual 3.0 Espanya de Creative Commons. Per

veure'n una còpia, visiteu http://creativecommons.org/licenses/by-sa/3.0/es/ o

envieu una carta a Creative Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA.