SlideShare uma empresa Scribd logo
1 de 196
Baixar para ler offline
16 mai 13
Test unitaire ?
Mock ? TDD ?
Kezako ?
1
Bienvenue !
❤=+
réseaux sociaux
Prochaines conférences : http://soat.fr
twitter : @soatgroup / @soatexpertsjava
slideshares : http://fr.slideshare.net/soatexpert
Aller plus loin : http://blog.soat.fr
Test unitaire ? Mock ? TDD ? Kezako ?
en finir avec les régressions par David Wursteisen
16 MAI 2013
Nouveau client !
Nouveau projet !
HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNG
LEGACY CODE
La documentation explique le code
/**
*
* @param xml : document xml représentant le swap
* @return objet Swap
*/
public Swap parse(String xml) {
Swap swap = new Swap();
String currency = getNodeValue("/swap/currency", xml);
swap.setCurrency(currency);
/* beaucoup de code... */
Date d = new Date();
if(test == 1) {
if(d.after(spotDate)) {
swap.setType("IRS");
} else {
swap.setType("CURVE");
}
} else if (test == 2) {
if(d.after(spotDate)) {
swap.setType("IRS");
} else {
swap.setType("CURVE");
}
}
/* encore beaucoup de code... */
return swap;
}
La documentation explique le code
1 /**
2 *
3 * @param xml : document xml représentant le swap
4 * @return objet Swap
5 */
6 public Swap parse(String xml) {
7 Swap swap = new Swap();
8 String currency = getNodeValue("/swap/currency", xml);
9 swap.setCurrency(currency);
[...] /* beaucoup de code... */
530 Date d = new Date();
531 if(test == 1) {
532 if(d.after(spotDate)) {
533 swap.setType("IRS");
534 } else {
535 swap.setType("CURVE");
536 }
537 } else if (test == 2) {
538 if(d.after(spotDate)) {
539 swap.setType("IRS");
540 } else {
541 swap.setType("CURVE");
542 }
543 }
[...] /* encore beaucoup de code... */
1135 return swap;
1136 }
1000
LIGNES !
La documentation a raison
1 /**
2 * Always returns true.
3 */
4 public boolean isAvailable() {
5 return false;
6 }
La documentation a raison
1 /**
2 * Always returns true.
3 */
4 public boolean isAvailable() {
5 return false;
6 }
WTF ?!?
La documentation n’est plus
fiable
une aide
utile
4 obj = networkService.getObject("product", id);
1 public Object getProduct(String id) {
2 Object obj = null;
3 try {
4 obj = networkService.getObject("product", id);
5 } catch (IOException e) {
6 System.err.println("Error with obj : " + obj.toString());
7 }
8 return obj;
9 }
Faire du code qui marche
4 obj = networkService.getObject("product", id);
1 public Object getProduct(String id) {
2 Object obj = null;
3 try {
4 obj = networkService.getObject("product", id);
5 } catch (IOException e) {
6 System.err.println("Error with obj : " + obj.toString());
7 }
8 return obj;
9 }
Faire du code qui marche
1 public Object getProduct(String id) {
2 Object obj = null;
3 try {
4 obj = networkService.getObject("product", id);
5 } catch (IOException e) {
6 System.err.println("Error with obj : " + obj.toString());
7 }
8 return obj;
9 }
2 Object obj = null;
5 } catch (IOException e) {
6 System.err.println("Error with obj : " + obj.toString());
7 }
Faire du code qui marche
NullPointerException !
4 account = (BankAccount) service.getProduct(this.name);
5 account.deposit();
1 public void affiche(BankAccount account, ProductService service) {
2 System.out.println("Bank Account : "+this.name);
3 System.out.println("Autres informations : ");
4 account = (BankAccount) service.getProduct(this.name);
5 account.deposit();
6 System.out.println(account);
7 System.out.println("=== FIN ===");
8
9 }
Code simple
HTTP://EN.WIKIPEDIA.ORG/WIKI/FILE:JEU_DE_MIKADO.JPG
4 account = (BankAccount) service.getProduct(this.name);
5 account.deposit();
1 public void affiche(BankAccount account, ProductService service) {
2 System.out.println("Bank Account : "+this.name);
3 System.out.println("Autres informations : ");
4 account = (BankAccount) service.getProduct(this.name);
5 account.deposit();
6 System.out.println(account);
7 System.out.println("=== FIN ===");
8
9 }
Code simple
HTTP://EN.WIKIPEDIA.ORG/WIKI/FILE:JEU_DE_MIKADO.JPG
4 account = (BankAccount) service.getProduct(this.name);
5 account.deposit();
1 public void affiche(BankAccount account, ProductService service) {
2 System.out.println("Bank Account : "+this.name);
3 System.out.println("Autres informations : ");
4 account = (BankAccount) service.getProduct(this.name);
5 account.deposit();
6 System.out.println(account);
7 System.out.println("=== FIN ===");
8
9 }
Code simple
HTTP://EN.WIKIPEDIA.ORG/WIKI/FILE:JEU_DE_MIKADO.JPG
C’est compliqué de faire
simple
un test
une évolution
Bonne nouvelle !
Je vous prend dans mon équipe !
HTTP://WWW.SXC.HU/PROFILE/HOTBLACK
COMMENT VA
T’ON POUVOIR
S’EN SORTIR ?
HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNG
TEST DRIVEN DEVELOPMENT
PRINCIPE DE BASE
Ecriture
du test
Lancement
du test
Ecriture
du test
Lancement
du test
Correction de
l’implémentation
Ecriture
du test
KO
Lancement
du test
Correction de
l’implémentation
Ecriture
du test
Fin
KO
OK
Lancement
du test
Correction de
l’implémentation
Ecriture
du test
Fin
KO
OK
REFACTOR
Toujours faire le test cassant avant
le test passant
(pour tester le test)
TEST UNITAIRE
tester la plus petite unité de code possible
TEST UNITAIRE
tester la plus petite unité de code possible
SIMPLE
TEST UNITAIRE
tester la plus petite unité de code possible
SIMPLEFEEDBACK
TEST UNITAIRE
tester la plus petite unité de code possible
SIMPLEFEEDBACKCOÛT
$400MILLIONS
EXEMPLE
1 @Test
2 public void can_deposit() {
3 bankAccount.setBalance(50);
4
5 boolean result = bankAccount.deposit(1000);
6
7 assertTrue(result);
8 assertEquals(1050, bankAccount.getBalance());
9 }
3 bankAccount.setBalance(50);
Test d’abord !
1 @Test
2 public void can_deposit() {
3 bankAccount.setBalance(50);
4
5 boolean result = bankAccount.deposit(1000);
6
7 assertTrue(result);
8 assertEquals(1050, bankAccount.getBalance());
9 }
3 bankAccount.setBalance(50);
Test d’abord !
5 boolean result = bankAccount.deposit(1000);
1 @Test
2 public void can_deposit() {
3 bankAccount.setBalance(50);
4
5 boolean result = bankAccount.deposit(1000);
6
7 assertTrue(result);
8 assertEquals(1050, bankAccount.getBalance());
9 }
Test d’abord !
1 @Test
2 public void can_deposit() {
3 bankAccount.setBalance(50);
4
5 boolean result = bankAccount.deposit(1000);
6
7 assertTrue(result);
8 assertEquals(1050, bankAccount.getBalance());
9 }
Test d’abord !
7 assertTrue(result);
8 assertEquals(1050, bankAccount.getBalance());
Test d’abord !
1 boolean deposit(int amount) {
2 return false;
3 }
Test d’abord !
1 boolean deposit(int amount) {
2 return false;
3 }
Test d’abord !
1 boolean deposit(int amount) {
2 bal = bal + amount;
3 return true;
4 }
Test d’abord !
1 boolean deposit(int amount) {
2 bal = bal + amount;
3 return true;
4 }
Test d’abord !
1 @Test
2 public void cant_deposit_with_negative_amount() {
3 bankAccount.setBalance(100);
4
5 boolean result = bankAccount.deposit(-20);
6
7 assertFalse(result);
8 assertEquals(100, bankAccount.getBalance());
9 }
Test d’abord !
1 @Test
2 public void cant_deposit_with_negative_amount() {
3 bankAccount.setBalance(100);
4
5 boolean result = bankAccount.deposit(-20);
6
7 assertFalse(result);
8 assertEquals(100, bankAccount.getBalance());
9 }
3 bankAccount.setBalance(100);
Test d’abord !
1 @Test
2 public void cant_deposit_with_negative_amount() {
3 bankAccount.setBalance(100);
4
5 boolean result = bankAccount.deposit(-20);
6
7 assertFalse(result);
8 assertEquals(100, bankAccount.getBalance());
9 }
5 boolean result = bankAccount.deposit(-20);
Test d’abord !
1 @Test
2 public void cant_deposit_with_negative_amount() {
3 bankAccount.setBalance(100);
4
5 boolean result = bankAccount.deposit(-20);
6
7 assertFalse(result);
8 assertEquals(100, bankAccount.getBalance());
9 }
7 assertFalse(result);
8 assertEquals(100, bankAccount.getBalance());
Test d’abord !
1 boolean deposit(int amount) {
2 bal = bal + amount;
3 return true;
4 }
Test d’abord !
1 boolean deposit(int amount) {
2 bal = bal + amount;
3 return true;
4 }
Test d’abord !
1 boolean deposit(int amount) {
2 if(amount < 0) {
3 return false;
4 }
5 bal = bal + amount;
6 return true;
7 }
Test d’abord !
1 boolean deposit(int amount) {
2 if(amount < 0) {
3 return false;
4 }
5 bal = bal + amount;
6 return true;
7 }
Acteur / Action / Assertion
les «3 A» : Acteur/Action/Assertion
1 @Test
2 public void cant_deposit_with_negative_amount() {
3 bankAccount.setBalance(100);
4
5 boolean result = bankAccount.deposit(-20);
6
7 assertFalse(result);
8 assertEquals(100, bankAccount.getBalance());
9 }
1 @Test
2 public void cant_deposit_with_negative_amount() {
3 bankAccount.setBalance(100);
4
5 boolean result = bankAccount.deposit(-20);
6
7 assertFalse(result);
8 assertEquals(100, bankAccount.getBalance());
9 }
les «3 A» : Acteur/Action/Assertion
3 bankAccount.setBalance(100);
Acteur
1 @Test
2 public void cant_deposit_with_negative_amount() {
3 bankAccount.setBalance(100);
4
5 boolean result = bankAccount.deposit(-20);
6
7 assertFalse(result);
8 assertEquals(100, bankAccount.getBalance());
9 }
les «3 A» : Acteur/Action/Assertion
5 boolean result = bankAccount.deposit(-20);
Action
1 @Test
2 public void cant_deposit_with_negative_amount() {
3 bankAccount.setBalance(100);
4
5 boolean result = bankAccount.deposit(-20);
6
7 assertFalse(result);
8 assertEquals(100, bankAccount.getBalance());
9 }
les «3 A» : Acteur/Action/Assertion
7 assertFalse(result);
8 assertEquals(100, bankAccount.getBalance());
Assertions
KISS
KISSKEEP IT SIMPLE (AND STUPID)
KISSKEEP IT SIMPLE (AND STUPID)
7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
8
9 // Vérifier.
10 Assert.assertNotNull("Extra non trouvé.", targetDTO);
11 Assert.assertEquals("Les accountId doivent être identiques.",
12 "ABC99", targetDTO.getAccountId());
1 @Test
2 public void testGetCustomerOK() {
3
4 LOGGER.info("======= testGetCustomerOK starting...");
5
6 try {
7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
8
9 // Vérifier.
10 Assert.assertNotNull("Extra non trouvé.", targetDTO);
11 Assert.assertEquals("Les accountId doivent être identiques.",
12 "ABC99", targetDTO.getAccountId());
13
14 } catch (CustomerBusinessException exception) {
15 LOGGER.error("CustomerBusinessException : {}",
16 exception.getCause());
17 Assert.fail(exception.getMessage());
18 } catch (UnavailableResourceException exception) {
19 LOGGER.error("UnavailableResourceException : {}",
20 exception.getMessage());
21 Assert.fail(exception.getMessage());
22 } catch (UnexpectedException exception) {
23 LOGGER.error("UnexpectedException : {}" +
24 exception.getMessage());
25 Assert.fail(exception.getMessage());
26 } catch (Exception exception) {
27 LOGGER.error("CRASH : " + exception.getMessage());
28 Assert.fail(exception.getMessage());
29 }
30
31 LOGGER.info("======= testGetCustomerOK done.");
32 }
7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
8
9 // Vérifier.
10 Assert.assertNotNull("Extra non trouvé.", targetDTO);
11 Assert.assertEquals("Les accountId doivent être identiques.",
12 "ABC99", targetDTO.getAccountId());
1 @Test
2 public void testGetCustomerOK() {
3
4 LOGGER.info("======= testGetCustomerOK starting...");
5
6 try {
7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
8
9 // Vérifier.
10 Assert.assertNotNull("Extra non trouvé.", targetDTO);
11 Assert.assertEquals("Les accountId doivent être identiques.",
12 "ABC99", targetDTO.getAccountId());
13
14 } catch (CustomerBusinessException exception) {
15 LOGGER.error("CustomerBusinessException : {}",
16 exception.getCause());
17 Assert.fail(exception.getMessage());
18 } catch (UnavailableResourceException exception) {
19 LOGGER.error("UnavailableResourceException : {}",
20 exception.getMessage());
21 Assert.fail(exception.getMessage());
22 } catch (UnexpectedException exception) {
23 LOGGER.error("UnexpectedException : {}" +
24 exception.getMessage());
25 Assert.fail(exception.getMessage());
26 } catch (Exception exception) {
27 LOGGER.error("CRASH : " + exception.getMessage());
28 Assert.fail(exception.getMessage());
29 }
30
31 LOGGER.info("======= testGetCustomerOK done.");
32 }
1 @Test
2 public void testGetCustomerOK() {
3
4 LOGGER.info("======= testGetCustomerOK starting...");
5
6 try {
7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
8
9 // Vérifier.
10 Assert.assertNotNull("Extra non trouvé.", targetDTO);
11 Assert.assertEquals("Les accountId doivent être identiques.",
12 "ABC99", targetDTO.getAccountId());
13
14 } catch (CustomerBusinessException exception) {
15 LOGGER.error("CustomerBusinessException : {}",
16 exception.getCause());
17 Assert.fail(exception.getMessage());
18 } catch (UnavailableResourceException exception) {
19 LOGGER.error("UnavailableResourceException : {}",
20 exception.getMessage());
21 Assert.fail(exception.getMessage());
22 } catch (UnexpectedException exception) {
23 LOGGER.error("UnexpectedException : {}" +
24 exception.getMessage());
25 Assert.fail(exception.getMessage());
26 } catch (Exception exception) {
27 LOGGER.error("CRASH : " + exception.getMessage());
28 Assert.fail(exception.getMessage());
29 }
30
31 LOGGER.info("======= testGetCustomerOK done.");
32 }
14 } catch (CustomerBusinessException exception) {
15 LOGGER.error("CustomerBusinessException : {}",
16 exception.getCause());
17 Assert.fail(exception.getMessage());
18 } catch (UnavailableResourceException exception) {
19 LOGGER.error("UnavailableResourceException : {}",
20 exception.getMessage());
21 Assert.fail(exception.getMessage());
22 } catch (UnexpectedException exception) {
23 LOGGER.error("UnexpectedException : {}" +
24 exception.getMessage());
25 Assert.fail(exception.getMessage());
26 } catch (Exception exception) {
27 LOGGER.error("CRASH : " + exception.getMessage());
28 Assert.fail(exception.getMessage());
29 }
30
31 LOGGER.info("======= testGetCustomerOK done.");
BRUIT
KISS !
1 @Test
2 public void can_get_customer() throws Exception {
3 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");
4 Assert.assertEquals("Les accountId doivent être identiques.",
5 "ABC99", targetDTO.getAccountId());
6 }
HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNG
EN PRATIQUE
VENIR ARMÉ
JUNIT + MOCKITO + ASSERTJ
JUNIT + MOCKITO + ASSERTJ
Mock ?
simulacre
se fait passer pour ce qu’il
n’est pas
comportement
paramétrable
MOCKITO
doReturn(new BankAccount()).when(daoService).getObject("product", "id");
doReturn(new BankAccount()).when(daoService).getObject("product", "id");doReturn(new BankAccount())
doReturn(new BankAccount()).when(daoService).getObject("product", "id");when(daoService)
doReturn(new BankAccount()).when(daoService).getObject("product", "id");getObject("product", "id");
doThrow(IOException.class).when(daoService).getObject("product", "id");
doThrow(IOException.class).when(daoService).getObject("product", "id");doThrow(IOException.class)
doThrow(IOException.class).when(daoService).getObject("product", "id");when(daoService)
doThrow(IOException.class).when(daoService).getObject("product", "id");getObject("product", "id");
ASSERTJ
assertThat(age).isGreaterThan(5);
assertThat(myList).containsExactly("MONAD42", "META18")
assertThat(negotation).isBooked();
NOUVEAU CODE = NOUVEAU TEST
NOUVEAU BUG = NOUVEAU TEST
nouveau bug = nouveau test
1 public Object getProduct(String id) {
2 Object obj = null;
3 try {
4 obj = networkService.getObject("product", id);
5 } catch (IOException e) {
6 System.err.println("Error with obj : " + obj.toString());
7 }
8 return obj;
9 }
1 public Object getProduct(String id) {
2 Object obj = null;
3 try {
4 obj = networkService.getObject("product", id);
5 } catch (IOException e) {
6 System.err.println("Error with obj : " + obj.toString());
7 }
8 return obj;
9 }
nouveau bug = nouveau test
6 System.err.println("Error with obj : " + obj.toString());
LE BUG EST ICI !
nouveau bug = nouveau test
1 @Test
2 public void can_return_null_when_ioexception() throws IOException {
3 Mockito.doThrow(IOException.class)
4 .when(networkService).getObject("product", "azerty");
5
6 Object product = service.getProduct("azerty");
7
8 assertThat(product).isNull();
9 }
3 Mockito.doThrow(IOException.class)
4 .when(networkService).getObject("product", "azerty");
1 @Test
2 public void can_return_null_when_ioexception() throws IOException {
3 Mockito.doThrow(IOException.class)
4 .when(networkService).getObject("product", "azerty");
5
6 Object product = service.getProduct("azerty");
7
8 assertThat(product).isNull();
9 }
nouveau bug = nouveau test
1 @Test
2 public void can_return_null_when_ioexception() throws IOException {
3 Mockito.doThrow(IOException.class)
4 .when(networkService).getObject("product", "azerty");
5
6 Object product = service.getProduct("azerty");
7
8 assertThat(product).isNull();
9 }
6 Object product = service.getProduct("azerty");
nouveau bug = nouveau test
8 assertThat(product).isNull();
1 @Test
2 public void can_return_null_when_ioexception() throws IOException {
3 Mockito.doThrow(IOException.class)
4 .when(networkService).getObject("product", "azerty");
5
6 Object product = service.getProduct("azerty");
7
8 assertThat(product).isNull();
9 }
nouveau bug = nouveau test
nouveau bug = nouveau test
1 public Object getProduct(String id) {
2 Object obj = null;
3 try {
4 obj = networkService.getObject("product", id);
5 } catch (IOException e) {
6 System.err.println("Error with obj : " + obj.toString());
7 }
8 return obj;
9 }
nouveau bug = nouveau test
1 public Object getProduct(String id) {
2 Object obj = null;
3 try {
4 obj = networkService.getObject("product", id);
5 } catch (IOException e) {
6 System.err.println("Error with obj : " + obj.toString());
7 }
8 return obj;
9 }
1 public Object getProduct(String id) {
2 Object obj = null;
3 try {
4 obj = networkService.getObject("product", id);
5 } catch (IOException e) {
6 System.err.println("Error with obj : " + obj.toString());
7 }
8 return obj;
9 }
nouveau bug = nouveau test
6 System.err.println("Error with obj : " + obj.toString());
LE BUG EST TOUJOURS ICI !
1 public Object getProduct(String id) {
2 Object obj = null;
3 try {
4 obj = networkService.getObject("product", id);
5 } catch (IOException e) {
6 System.err.println("Error with obj with id: " + id);
7 }
8 return obj;
9 }
nouveau bug = nouveau test
6 System.err.println("Error with obj with id: " + id);
nouveau bug = nouveau test
1 public Object getProduct(String id) {
2 Object obj = null;
3 try {
4 obj = networkService.getObject("product", id);
5 } catch (IOException e) {
6 System.err.println("Error with obj with id: " + id);
7 }
8 return obj;
9 }
6 System.err.println("Error with obj with id: " + id);
Laissez votre câble tranquille
TESTER DOIT ÊTRE SIMPLE
code complexe
1 /**
2 *
3 * @param xml : document xml représentant le swap
4 * @return objet Swap
5 */
6 public Swap parse(String xml) {
7 Swap swap = new Swap();
8 String currency = getNodeValue("/swap/currency", xml);
9 swap.setCurrency(currency);
[...] /* beaucoup de code... */
530 Date d = new Date();
531 if(test == 1) {
532 if(d.after(spotDate)) {
533 swap.setType("IRS");
534 } else {
535 swap.setType("CURVE");
536 }
537 } else if (test == 2) {
538 if(d.after(spotDate)) {
539 swap.setType("IRS");
540 } else {
541 swap.setType("CURVE");
542 }
543 }
[...] /* encore beaucoup de code... */
1135 return swap;
1136 }
1 @Test
2 public void can_parse_xml() throws Exception {
3 String xml = "<?xml version="1.0" encoding="UTF-8"?>n" +
4 "<!--n" +
5 "t== Copyright (c) 2002-2005. All rights reserved.n" +
6 "t== Financial Products Markup Language is subject to the FpML public license.n" +
7 "t== A copy of this license is available at http://www.fpml.org/documents/licensen" +
8 "-->n" +
9 "<FpML version="4-2" xmlns="http://www.fpml.org/2005/FpML-4-2" xmlns:xsi="http://www.w3.org/2001/
XMLSchema-instance" xsi:schemaLocation="http://www.fpml.org/2005/FpML-4-2 fpml-main-4-2.xsd" xsi:type=
"TradeCashflowsAsserted">n" +
10 "t<header>n" +
11 "tt<messageId messageIdScheme="http://www.example.com/messageId">CEN/2004/01/05/15-38</messageId>n"
+
12 "tt<sentBy>ABC</sentBy>n" +
13 "tt<sendTo>DEF</sendTo>n" +
14 "tt<creationTimestamp>2005-01-05T15:38:00-00:00</creationTimestamp>n" +
15 "t</header>n" +
16 "t<asOfDate>2005-01-05T15:00:00-00:00</asOfDate>n" +
17 "t<tradeIdentifyingItems>n" +
18 "tt<partyTradeIdentifier>n" +
19 "ttt<partyReference href="abc"/>n" +
20 "ttt<tradeId tradeIdScheme="http://www.abc.com/tradeId/">trade1abcxxx</tradeId>n" +
21 "tt</partyTradeIdentifier>n" +
22 "tt<partyTradeIdentifier>n" +
23 "ttt<partyReference href="def"/>n" +
24 "ttt<tradeId tradeIdScheme="http://www.def.com/tradeId/">123cds</tradeId>n" +
25 "tt</partyTradeIdentifier>n" +
26 "t</tradeIdentifyingItems>n" +
27 "t<adjustedPaymentDate>2005-01-31</adjustedPaymentDate>n" +
28 "t<netPayment>n" +
29 "tt<identifier netPaymentIdScheme="http://www.centralservice.com/netPaymentId">netPaymentABCDEF001</
identifier>n" +
30 "tt<payerPartyReference href="abc"/>n" +
31 "tt<receiverPartyReference href="def"/>n" +
32 "tt<paymentAmount>n" +
code complexe
1 /**
2 *
3 * @param xml : document xml représentant le swap
4 * @return objet Swap
5 */
6 public Swap parse(String xml) {
7 Swap swap = new Swap();
8 String currency = getNodeValue("/swap/currency", xml);
9 swap.setCurrency(currency);
[...] /* beaucoup de code... */
530 Date d = new Date();
531 if(test == 1) {
532 if(d.after(spotDate)) {
533 swap.setType("IRS");
534 } else {
535 swap.setType("CURVE");
536 }
537 } else if (test == 2) {
538 if(d.after(spotDate)) {
539 swap.setType("IRS");
540 } else {
541 swap.setType("CURVE");
542 }
543 }
[...] /* encore beaucoup de code... */
1135 return swap;
1136 }
1 /**
2 *
3 * @param xml : document xml représentant le swap
4 * @return objet Swap
5 */
6 public Swap parse(String xml) {
7 Swap swap = new Swap();
8 String currency = getNodeValue("/swap/currency", xml);
9 swap.setCurrency(currency);
[...] /* beaucoup de code... */
530 Date d = new Date();
531 if(test == 1) {
532 if(d.after(spotDate)) {
533 swap.setType("IRS");
534 } else {
535 swap.setType("CURVE");
536 }
537 } else if (test == 2) {
538 if(d.after(spotDate)) {
539 swap.setType("IRS");
540 } else {
541 swap.setType("CURVE");
542 }
543 }
[...] /* encore beaucoup de code... */
1135 return swap;
1136 }
code complexe
531 if(test == 1) {
532 if(d.after(spotDate)) {
533 swap.setType("IRS");
534 } else {
535 swap.setType("CURVE");
536 }
537 } else if (test == 2) {
538 if(d.after(spotDate)) {
539 swap.setType("IRS");
540 } else {
541 swap.setType("CURVE");
542 }
543 }
EXTRACT METHOD !
code complexe
1 public void updateSwapType(Swap swapToUpdate, Date now, Date spotDate, int test) {
2 if(test == 1) {
3 if(now.after(spotDate)) {
4 swapToUpdate.setType("IRS");
5 } else {
6 swapToUpdate.setType("CURVE");
7 }
8 } else if (test == 2) {
9 if(now.after(spotDate)) {
10 swapToUpdate.setType("IRS");
11 } else {
12 swapToUpdate.setType("CURVE");
13 }
14 }
15 }
code complexe
1 @Test
2 public void can_update_swap_type() throws Exception {
3 Swap swap = new Swap();
4 Date now = simpleDateFormat.parse("2012-06-15");
5 Date before = simpleDateFormat.parse("2012-05-05");
6 service.updateSwapType(swap, now, before, 1);
7 assertEquals("IRS", swap.getType());
8 }
LE CODE DOIT ÊTRE MODULAIRE
Singleton
1 public class ProductService {
2
3 private static ProductService instance = new ProductService();
4
5 private DAOService daoService;
6
7 private ProductService() {
8 System.out.println("ProductService constructor");
9 daoService = DAOService.getInstance();
10 }
11
12 public static ProductService getInstance() {
13 return instance;
14 }
15
16
17
18 public Object getProduct(String id) {
19 return daoService.getObject("product", id);
20 }
21 }
1 public class ProductService {
2
3 private static ProductService instance = new ProductService();
4
5 private DAOService daoService;
6
7 private ProductService() {
8 System.out.println("ProductService constructor");
9 daoService = DAOService.getInstance();
10 }
11
12 public static ProductService getInstance() {
13 return instance;
14 }
15
16
17
18 public Object getProduct(String id) {
19 return daoService.getObject("product", id);
20 }
21 }
Singleton
3 private static ProductService instance = new ProductService();
1 public class ProductService {
2
3 private static ProductService instance = new ProductService();
4
5 private DAOService daoService;
6
7 private ProductService() {
8 System.out.println("ProductService constructor");
9 daoService = DAOService.getInstance();
10 }
11
12 public static ProductService getInstance() {
13 return instance;
14 }
15
16
17
18 public Object getProduct(String id) {
19 return daoService.getObject("product", id);
20 }
21 }
Singleton
7 private ProductService() {
9 daoService = DAOService.getInstance();
10 }
Singleton
1 public class ProductService {
2
3 private static ProductService instance = new ProductService();
4
5 private DAOService daoService;
6
7 private ProductService() {
8 System.out.println("ProductService constructor");
9 daoService = DAOService.getInstance();
10 }
11
12 public static ProductService getInstance() {
13 return instance;
14 }
15
16
17
18 public Object getProduct(String id) {
19 return daoService.getObject("product", id);
20 }
21 }
Singleton
Code
Singleton
Code ProductService
Singleton
Code ProductService DAOService
Singleton
Code ProductService DAOService
Singleton
Code ProductService DAOService
Singleton
Code ProductService DAOService
Mock
ProductService
Singleton
1 public void validateSwap(String id) {
2 Swap swap = (Swap) ProductService.getInstance().getProduct(id);
3 swap.updateState("VALIDATE");
4 ProductService.getInstance().save(swap);
5 }
1 public void validateSwap(String id) {
2 Swap swap = (Swap) ProductService.getInstance().getProduct(id);
3 swap.updateState("VALIDATE");
4 ProductService.getInstance().save(swap);
5 }
Singleton
ProductService.getInstance()
4 ProductService.getInstance()
COUPLAGE FORT
Injection
1 private ProductService productService;
2
3 public void setProductService(ProductService injectedService) {
4 this.productService = injectedService;
5 }
6
7 public void validateSwap(String id) {
8 Swap swap = (Swap) productService.getProduct(id);
9 swap.updateState("VALIDATE");
10 productService.save(swap);
11 }
1 private ProductService productService;
2
3 public void setProductService(ProductService injectedService) {
4 this.productService = injectedService;
5 }
6
7 public void validateSwap(String id) {
8 Swap swap = (Swap) productService.getProduct(id);
9 swap.updateState("VALIDATE");
10 productService.save(swap);
11 }
Injection
3 public void setProductService(ProductService injectedService) {
4 this.productService = injectedService;
5 }
INJECTION
1 private ProductService productService;
2
3 public void setProductService(ProductService injectedService) {
4 this.productService = injectedService;
5 }
6
7 public void validateSwap(String id) {
8 Swap swap = (Swap) productService.getProduct(id);
9 swap.updateState("VALIDATE");
10 productService.save(swap);
11 }
Injection
8 Swap swap = (Swap) productService.getProduct(id);
UTILISATION
Injection
1 @InjectMocks
2 private BankAccount bankAccount;
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
12 Mockito.doNothing().when(productService).save(swap);
13
14 bankAccount.validateSwap("fakeId");
15
16 assertEquals("VALIDATE", swap.getState());
17 }
1 @InjectMocks
2 private BankAccount bankAccount;
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
12 Mockito.doNothing().when(productService).save(swap);
13
14 bankAccount.validateSwap("fakeId");
15
16 assertEquals("VALIDATE", swap.getState());
17 }
Injection
4 @Mock
5 private ProductService productService;
MOCK
1 @InjectMocks
2 private BankAccount bankAccount;
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
12 Mockito.doNothing().when(productService).save(swap);
13
14 bankAccount.validateSwap("fakeId");
15
16 assertEquals("VALIDATE", swap.getState());
17 }
Injection
1 @InjectMocks
2 private BankAccount bankAccount;
INJECTION AUTOMATIQUE
DES MOCKS
1 @InjectMocks
2 private BankAccount bankAccount;
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
12 Mockito.doNothing().when(productService).save(swap);
13
14 bankAccount.validateSwap("fakeId");
15
16 assertEquals("VALIDATE", swap.getState());
17 }
Injection
11 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
12 Mockito.doNothing().when(productService).save(swap);
1 @InjectMocks
2 private BankAccount bankAccount;
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
12 Mockito.doNothing().when(productService).save(swap);
13
14 bankAccount.validateSwap("fakeId");
15
16 assertEquals("VALIDATE", swap.getState());
17 }
14 bankAccount.validateSwap("fakeId");
Injection
Injection
1 @InjectMocks
2 private BankAccount bankAccount;
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
12 Mockito.doNothing().when(productService).save(swap);
13
14 bankAccount.validateSwap("fakeId");
15
16 assertEquals("VALIDATE", swap.getState());
17 }
16 assertEquals("VALIDATE", swap.getState());
YODA (C) DISNEY
UTILISE L’INJECTION,
LUKE
YODA (C) DISNEY
Sans injecteur ?
1 public void validateSwap(String id) {
2 Swap swap = (Swap) ProductService.getInstance().getProduct(id);
3 swap.updateState("VALIDATE");
4 ProductService.getInstance().save(swap);
5 }
1 public void validateSwap(String id) {
2 Swap swap = (Swap) ProductService.getInstance().getProduct(id);
3 swap.updateState("VALIDATE");
4 ProductService.getInstance().save(swap);
5 }
Sans injecteur ?
ProductService.getInstance()
4 ProductService.getInstance()
EXTRACT METHOD !
1 public ProductService getProductService() {
2 return ProductService.getInstance();
3 }
4
5 public void validateSwap(String id) {
6 Swap swap = (Swap) getProductService().getProduct(id);
7 swap.updateState("VALIDATE");
8 getProductService().save(swap);
9 }
Sans injecteur ?
1 public ProductService getProductService() {
2 return ProductService.getInstance();
3 }
getProductService()
8 getProductService()
Sans injecteur ?
1 @Spy
2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(productService).when(bankAccount).getProductService();
12
13 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
14 Mockito.doNothing().when(productService).save(swap);
15
16 bankAccount.validateSwap("fakeId");
17
18 assertEquals("VALIDATE", swap.getState());
19 }
1 @Spy
2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(productService).when(bankAccount).getProductService();
12
13 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
14 Mockito.doNothing().when(productService).save(swap);
15
16 bankAccount.validateSwap("fakeId");
17
18 assertEquals("VALIDATE", swap.getState());
19 }
Sans injecteur ?
1 @Spy
2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);
REDÉFINITION DES MÉTHODES
POSSIBLE
1 @Spy
2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(productService).when(bankAccount).getProductService();
12
13 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
14 Mockito.doNothing().when(productService).save(swap);
15
16 bankAccount.validateSwap("fakeId");
17
18 assertEquals("VALIDATE", swap.getState());
19 }
Sans injecteur ?
11 Mockito.doReturn(productService).when(bankAccount).getProductService();
1 @Spy
2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(productService).when(bankAccount).getProductService();
12
13 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
14 Mockito.doNothing().when(productService).save(swap);
15
16 bankAccount.validateSwap("fakeId");
17
18 assertEquals("VALIDATE", swap.getState());
19 }
Sans injecteur ?
13 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
14 Mockito.doNothing().when(productService).save(swap);
Sans injecteur ?
1 @Spy
2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(productService).when(bankAccount).getProductService();
12
13 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
14 Mockito.doNothing().when(productService).save(swap);
15
16 bankAccount.validateSwap("fakeId");
17
18 assertEquals("VALIDATE", swap.getState());
19 }
16 bankAccount.validateSwap("fakeId");
Sans injecteur ?
1 @Spy
2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);
3
4 @Mock
5 private ProductService productService;
6
7 @Test
8 public void can_validate_swap() {
9 Swap swap = new Swap();
10
11 Mockito.doReturn(productService).when(bankAccount).getProductService();
12
13 Mockito.doReturn(swap).when(productService).getProduct("fakeId");
14 Mockito.doNothing().when(productService).save(swap);
15
16 bankAccount.validateSwap("fakeId");
17
18 assertEquals("VALIDATE", swap.getState());
19 }
18 assertEquals("VALIDATE", swap.getState());
Avertissement
LANCER UN TEST DOIT ÊTRE FACILE
Tests dans son IDE
ECLIPSE
NETBEANS
INTELLIJ
LE CODE DOIT TOUJOURS
ÊTRE DÉPLOYABLE
Intégration continue
mvn install
Intégration continue
[INFO] ---------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ---------------------------------------------
Intégration continue
mvn install
Intégration continue
[INFO] ---------------------------------------------
[INFO] BUILD FAILURE
[INFO] ---------------------------------------------
Intégration continue
[INFO] ---------------------------------------------
[INFO] BUILD FAILURE
[INFO] ---------------------------------------------
WORKS ON
MY
MACHINE
Intégration continue
Déclenchement
d’un build
Intégration continue
Déclenchement
d’un build
Compilation
Intégration continue
Déclenchement
d’un build
Compilation Test
Intégration continue
Déclenchement
d’un build
Compilation Test
Déploiement
Analyse de code
AVOIR LA BONNE COUVERTURE
80%DE COUVERTURE DE CODE
80%DE COUVERTURE DE GETTER/SETTER
TRAVAILLER EN BINÔME
binomage (pair hero)
philosophie différente pour code identique
HTTP://WWW.SXC.HU/PHOTO/959091
binomage (pair hero)
philosophie différente pour code identiqueLES COMMANDES
binomage (pair hero)
philosophie différente pour code identique
LE PLAN DE VOL
Ping Pong
J’écris le test
Il écrit l’implémentation
J’écris le test
Il écrit l’implémentation
bref
j’ai binômé
6 mois plus tard...
Bugs
0
22,5
45
67,5
90
Janvier Février Mars Avril Mai Juin
Bugs Satisfaction
Bugs
0
22,5
45
67,5
90
Janvier Février Mars Avril Mai Juin
Bugs Satisfaction
Bugs
0
22,5
45
67,5
90
Janvier Février Mars Avril Mai Juin
Bugs Satisfaction
Bugs
0
22,5
45
67,5
90
Janvier Février Mars Avril Mai Juin
Bugs Satisfaction
Bugs
0
22,5
45
67,5
90
Janvier Février Mars Avril Mai Juin
Bugs Satisfaction
Bugs
0
22,5
45
67,5
90
Janvier Février Mars Avril Mai Juin
Bugs Satisfaction
BRAVO À NOTRE ÉQUIPE DE CHOC !
(POUR RÉSUMER)
Installez Jenkins
Automatisez votre build
Écrivez votre 1er test
(même si il est «trop» simple)
HTTP://WWW.SXC.HU/PHOTO/664214
IL FAUT APPRENDRE
À NAGER...
...AVANT DE GAGNER
DES COMPÉTITIONS
HTTP://WWW.SXC.HU/PHOTO/1008962
( DEMO )
HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNG
QUESTIONS ?
Merci !
It’s Pizza Time !Drink
@DWURSTEISEN
référence
jenkins : http://jenkins-ci.org/
assertj : https://github.com/joel-costigliola/assertj
mockito : https://code.google.com/p/mockito/
démo : http://parleys.com/play/5148922a0364bc17fc56c85a/about

Mais conteúdo relacionado

Mais procurados

33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
Tomek Kaczanowski
 
NetBeans Plugin Development: JRebel Experience Report
NetBeans Plugin Development: JRebel Experience ReportNetBeans Plugin Development: JRebel Experience Report
NetBeans Plugin Development: JRebel Experience Report
Anton Arhipov
 

Mais procurados (20)

LISA QooxdooTutorial Slides
LISA QooxdooTutorial SlidesLISA QooxdooTutorial Slides
LISA QooxdooTutorial Slides
 
Jasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishyJasmine - why JS tests don't smell fishy
Jasmine - why JS tests don't smell fishy
 
33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests33rd Degree 2013, Bad Tests, Good Tests
33rd Degree 2013, Bad Tests, Good Tests
 
The Ring programming language version 1.10 book - Part 94 of 212
The Ring programming language version 1.10 book - Part 94 of 212The Ring programming language version 1.10 book - Part 94 of 212
The Ring programming language version 1.10 book - Part 94 of 212
 
Object oriented JavaScript
Object oriented JavaScriptObject oriented JavaScript
Object oriented JavaScript
 
Javascript Testing with Jasmine 101
Javascript Testing with Jasmine 101Javascript Testing with Jasmine 101
Javascript Testing with Jasmine 101
 
Extreme JavaScript Performance
Extreme JavaScript PerformanceExtreme JavaScript Performance
Extreme JavaScript Performance
 
Node.js flow control
Node.js flow controlNode.js flow control
Node.js flow control
 
Dat testing - An introduction to Java and Android Testing
Dat testing - An introduction to Java and Android TestingDat testing - An introduction to Java and Android Testing
Dat testing - An introduction to Java and Android Testing
 
The Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 SeasonsThe Groovy Puzzlers – The Complete 01 and 02 Seasons
The Groovy Puzzlers – The Complete 01 and 02 Seasons
 
Kotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan SoaresKotlin : Advanced Tricks - Ubiratan Soares
Kotlin : Advanced Tricks - Ubiratan Soares
 
Rich and Snappy Apps (No Scaling Required)
Rich and Snappy Apps (No Scaling Required)Rich and Snappy Apps (No Scaling Required)
Rich and Snappy Apps (No Scaling Required)
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
 
NetBeans Plugin Development: JRebel Experience Report
NetBeans Plugin Development: JRebel Experience ReportNetBeans Plugin Development: JRebel Experience Report
NetBeans Plugin Development: JRebel Experience Report
 
The Promised Land (in Angular)
The Promised Land (in Angular)The Promised Land (in Angular)
The Promised Land (in Angular)
 
Understanding JavaScript Testing
Understanding JavaScript TestingUnderstanding JavaScript Testing
Understanding JavaScript Testing
 
Taking a Test Drive
Taking a Test DriveTaking a Test Drive
Taking a Test Drive
 
Testing My Patience
Testing My PatienceTesting My Patience
Testing My Patience
 
201913001 khairunnisa progres_harian
201913001 khairunnisa progres_harian201913001 khairunnisa progres_harian
201913001 khairunnisa progres_harian
 
Fia fabila
Fia fabilaFia fabila
Fia fabila
 

Destaque

Destaque (8)

Amélioration continue, c'est l'affaire de tous !
Amélioration continue, c'est l'affaire de tous !Amélioration continue, c'est l'affaire de tous !
Amélioration continue, c'est l'affaire de tous !
 
JAVA 8 : Migration et enjeux stratégiques en entreprise
JAVA 8 : Migration et enjeux stratégiques en entrepriseJAVA 8 : Migration et enjeux stratégiques en entreprise
JAVA 8 : Migration et enjeux stratégiques en entreprise
 
3/3 : The path to CDI 2.0 - Antoine Sabot-Durand
3/3 : The path to CDI 2.0 - Antoine Sabot-Durand3/3 : The path to CDI 2.0 - Antoine Sabot-Durand
3/3 : The path to CDI 2.0 - Antoine Sabot-Durand
 
1/3 : introduction to CDI - Antoine Sabot-Durand
1/3 : introduction to CDI - Antoine Sabot-Durand1/3 : introduction to CDI - Antoine Sabot-Durand
1/3 : introduction to CDI - Antoine Sabot-Durand
 
Test unitaire
Test unitaireTest unitaire
Test unitaire
 
L'entreprise libérée
L'entreprise libéréeL'entreprise libérée
L'entreprise libérée
 
Test unitaires visual studio
Test unitaires visual studioTest unitaires visual studio
Test unitaires visual studio
 
ARCHITECTURE MICROSERVICE : TOUR D’HORIZON DU CONCEPT ET BONNES PRATIQUES
ARCHITECTURE MICROSERVICE : TOUR D’HORIZON DU CONCEPT ET BONNES PRATIQUESARCHITECTURE MICROSERVICE : TOUR D’HORIZON DU CONCEPT ET BONNES PRATIQUES
ARCHITECTURE MICROSERVICE : TOUR D’HORIZON DU CONCEPT ET BONNES PRATIQUES
 

Semelhante a Tests unitaires mock_kesako_20130516

Boosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyBoosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with Groovy
James Williams
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Robot Media
 

Semelhante a Tests unitaires mock_kesako_20130516 (20)

Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113Conf soat tests_unitaires_Mockito_jUnit_170113
Conf soat tests_unitaires_Mockito_jUnit_170113
 
Como NÃO testar o seu projeto de Software. DevDay 2014
Como NÃO testar o seu projeto de Software. DevDay 2014Como NÃO testar o seu projeto de Software. DevDay 2014
Como NÃO testar o seu projeto de Software. DevDay 2014
 
Tdd iPhone For Dummies
Tdd iPhone For DummiesTdd iPhone For Dummies
Tdd iPhone For Dummies
 
Google guava
Google guavaGoogle guava
Google guava
 
An Introduction to Property Based Testing
An Introduction to Property Based TestingAn Introduction to Property Based Testing
An Introduction to Property Based Testing
 
Javascript Everywhere
Javascript EverywhereJavascript Everywhere
Javascript Everywhere
 
Aaron Bedra - Effective Software Security Teams
Aaron Bedra - Effective Software Security TeamsAaron Bedra - Effective Software Security Teams
Aaron Bedra - Effective Software Security Teams
 
Boosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with GroovyBoosting Your Testing Productivity with Groovy
Boosting Your Testing Productivity with Groovy
 
Javaone2008 Bof 5101 Groovytesting
Javaone2008 Bof 5101 GroovytestingJavaone2008 Bof 5101 Groovytesting
Javaone2008 Bof 5101 Groovytesting
 
Construire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradleConstruire une application JavaFX 8 avec gradle
Construire une application JavaFX 8 avec gradle
 
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMockUnit testing in iOS featuring OCUnit, GHUnit & OCMock
Unit testing in iOS featuring OCUnit, GHUnit & OCMock
 
Testing the waters of iOS
Testing the waters of iOSTesting the waters of iOS
Testing the waters of iOS
 
Test Infected Presentation
Test Infected PresentationTest Infected Presentation
Test Infected Presentation
 
A Lifecycle Of Code Under Test by Robert Fornal
A Lifecycle Of Code Under Test by Robert FornalA Lifecycle Of Code Under Test by Robert Fornal
A Lifecycle Of Code Under Test by Robert Fornal
 
PHPunit and you
PHPunit and youPHPunit and you
PHPunit and you
 
Developer Test - Things to Know
Developer Test - Things to KnowDeveloper Test - Things to Know
Developer Test - Things to Know
 
04 - Dublerzy testowi
04 - Dublerzy testowi04 - Dublerzy testowi
04 - Dublerzy testowi
 
Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?
Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?
Connect2017 DEV-1550 Why Java 8? Or, What's a Lambda?
 
DEV-1550: Why Java 8? Or, What's a Lambda? – IBM Connect 2017
DEV-1550: Why Java 8? Or, What's a Lambda? – IBM Connect 2017DEV-1550: Why Java 8? Or, What's a Lambda? – IBM Connect 2017
DEV-1550: Why Java 8? Or, What's a Lambda? – IBM Connect 2017
 
We Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End DevelopmentWe Are All Testers Now: The Testing Pyramid and Front-End Development
We Are All Testers Now: The Testing Pyramid and Front-End Development
 

Mais de SOAT

20140123 java8 lambdas_jose-paumard-soat
20140123 java8 lambdas_jose-paumard-soat20140123 java8 lambdas_jose-paumard-soat
20140123 java8 lambdas_jose-paumard-soat
SOAT
 
Soirée 3T Soat - Asp.net MVC
Soirée 3T Soat - Asp.net MVCSoirée 3T Soat - Asp.net MVC
Soirée 3T Soat - Asp.net MVC
SOAT
 
Présentation spring data Matthieu Briend
Présentation spring data  Matthieu BriendPrésentation spring data  Matthieu Briend
Présentation spring data Matthieu Briend
SOAT
 

Mais de SOAT (20)

Back from Microsoft //Build 2018
Back from Microsoft //Build 2018Back from Microsoft //Build 2018
Back from Microsoft //Build 2018
 
2/3 : CDI advanced - Antoine Sabot-Durand
2/3 : CDI advanced - Antoine Sabot-Durand2/3 : CDI advanced - Antoine Sabot-Durand
2/3 : CDI advanced - Antoine Sabot-Durand
 
Angular JS - Paterne Gaye-Guingnido
Angular JS - Paterne Gaye-Guingnido Angular JS - Paterne Gaye-Guingnido
Angular JS - Paterne Gaye-Guingnido
 
Dans l'enfer du Web Mobile - un retour d'expérience - Mathieu Parisot
Dans l'enfer du Web Mobile - un retour d'expérience - Mathieu ParisotDans l'enfer du Web Mobile - un retour d'expérience - Mathieu Parisot
Dans l'enfer du Web Mobile - un retour d'expérience - Mathieu Parisot
 
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
 
L'impact du Responsive Web Design sur vos équipes projet - Mathieu Parisot - ...
L'impact du Responsive Web Design sur vos équipes projet - Mathieu Parisot - ...L'impact du Responsive Web Design sur vos équipes projet - Mathieu Parisot - ...
L'impact du Responsive Web Design sur vos équipes projet - Mathieu Parisot - ...
 
Nio sur Netty par Mouhcine Moulou - 3 avril 2014
Nio sur Netty par Mouhcine Moulou - 3 avril 2014Nio sur Netty par Mouhcine Moulou - 3 avril 2014
Nio sur Netty par Mouhcine Moulou - 3 avril 2014
 
20140123 java8 lambdas_jose-paumard-soat
20140123 java8 lambdas_jose-paumard-soat20140123 java8 lambdas_jose-paumard-soat
20140123 java8 lambdas_jose-paumard-soat
 
Développer des applications iOS et Android avec c# grâce à Xamarin par Cyril ...
Développer des applications iOS et Android avec c# grâce à Xamarin par Cyril ...Développer des applications iOS et Android avec c# grâce à Xamarin par Cyril ...
Développer des applications iOS et Android avec c# grâce à Xamarin par Cyril ...
 
Amazon Web Service par Bertrand Lehurt - 11 mars 2014
Amazon Web Service par Bertrand Lehurt - 11 mars 2014Amazon Web Service par Bertrand Lehurt - 11 mars 2014
Amazon Web Service par Bertrand Lehurt - 11 mars 2014
 
ASP.Net Web API - Léonard Labat (18 février 2014)
ASP.Net Web API - Léonard Labat (18 février 2014)ASP.Net Web API - Léonard Labat (18 février 2014)
ASP.Net Web API - Léonard Labat (18 février 2014)
 
Xamarin et le développement natif d’applications Android, iOS et Windows en C#
 Xamarin et le développement natif d’applications Android, iOS et Windows en C# Xamarin et le développement natif d’applications Android, iOS et Windows en C#
Xamarin et le développement natif d’applications Android, iOS et Windows en C#
 
A la découverte du Responsive Web Design par Mathieu Parisot - Soat
A la découverte du Responsive Web Design par Mathieu Parisot - SoatA la découverte du Responsive Web Design par Mathieu Parisot - Soat
A la découverte du Responsive Web Design par Mathieu Parisot - Soat
 
MongoDB : la base NoSQL qui réinvente la gestion de données
MongoDB : la base NoSQL qui réinvente la gestion de donnéesMongoDB : la base NoSQL qui réinvente la gestion de données
MongoDB : la base NoSQL qui réinvente la gestion de données
 
Soirée 3T Soat - Asp.net MVC
Soirée 3T Soat - Asp.net MVCSoirée 3T Soat - Asp.net MVC
Soirée 3T Soat - Asp.net MVC
 
Présentation spring data Matthieu Briend
Présentation spring data  Matthieu BriendPrésentation spring data  Matthieu Briend
Présentation spring data Matthieu Briend
 
Je suis agile tout seul - Ricardo Minhoto
Je suis agile tout seul - Ricardo MinhotoJe suis agile tout seul - Ricardo Minhoto
Je suis agile tout seul - Ricardo Minhoto
 
Facilitez vous la vie - Ricardo Minhoto
Facilitez vous la vie - Ricardo MinhotoFacilitez vous la vie - Ricardo Minhoto
Facilitez vous la vie - Ricardo Minhoto
 
Play : Premiers pas par l'exemple le 120613
Play : Premiers pas par l'exemple le 120613Play : Premiers pas par l'exemple le 120613
Play : Premiers pas par l'exemple le 120613
 
Transition Agile technique à grande échelle
Transition Agile technique à grande échelleTransition Agile technique à grande échelle
Transition Agile technique à grande échelle
 

Último

CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
giselly40
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
vu2urc
 

Último (20)

ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 

Tests unitaires mock_kesako_20130516

  • 1. 16 mai 13 Test unitaire ? Mock ? TDD ? Kezako ? 1
  • 4. réseaux sociaux Prochaines conférences : http://soat.fr twitter : @soatgroup / @soatexpertsjava slideshares : http://fr.slideshare.net/soatexpert Aller plus loin : http://blog.soat.fr
  • 5. Test unitaire ? Mock ? TDD ? Kezako ? en finir avec les régressions par David Wursteisen 16 MAI 2013
  • 6.
  • 7.
  • 10.
  • 11.
  • 13. La documentation explique le code /** * * @param xml : document xml représentant le swap * @return objet Swap */ public Swap parse(String xml) { Swap swap = new Swap(); String currency = getNodeValue("/swap/currency", xml); swap.setCurrency(currency); /* beaucoup de code... */ Date d = new Date(); if(test == 1) { if(d.after(spotDate)) { swap.setType("IRS"); } else { swap.setType("CURVE"); } } else if (test == 2) { if(d.after(spotDate)) { swap.setType("IRS"); } else { swap.setType("CURVE"); } } /* encore beaucoup de code... */ return swap; }
  • 14. La documentation explique le code 1 /** 2 * 3 * @param xml : document xml représentant le swap 4 * @return objet Swap 5 */ 6 public Swap parse(String xml) { 7 Swap swap = new Swap(); 8 String currency = getNodeValue("/swap/currency", xml); 9 swap.setCurrency(currency); [...] /* beaucoup de code... */ 530 Date d = new Date(); 531 if(test == 1) { 532 if(d.after(spotDate)) { 533 swap.setType("IRS"); 534 } else { 535 swap.setType("CURVE"); 536 } 537 } else if (test == 2) { 538 if(d.after(spotDate)) { 539 swap.setType("IRS"); 540 } else { 541 swap.setType("CURVE"); 542 } 543 } [...] /* encore beaucoup de code... */ 1135 return swap; 1136 } 1000 LIGNES !
  • 15. La documentation a raison 1 /** 2 * Always returns true. 3 */ 4 public boolean isAvailable() { 5 return false; 6 }
  • 16. La documentation a raison 1 /** 2 * Always returns true. 3 */ 4 public boolean isAvailable() { 5 return false; 6 } WTF ?!?
  • 17. La documentation n’est plus fiable une aide utile
  • 18. 4 obj = networkService.getObject("product", id); 1 public Object getProduct(String id) { 2 Object obj = null; 3 try { 4 obj = networkService.getObject("product", id); 5 } catch (IOException e) { 6 System.err.println("Error with obj : " + obj.toString()); 7 } 8 return obj; 9 } Faire du code qui marche
  • 19. 4 obj = networkService.getObject("product", id); 1 public Object getProduct(String id) { 2 Object obj = null; 3 try { 4 obj = networkService.getObject("product", id); 5 } catch (IOException e) { 6 System.err.println("Error with obj : " + obj.toString()); 7 } 8 return obj; 9 } Faire du code qui marche
  • 20. 1 public Object getProduct(String id) { 2 Object obj = null; 3 try { 4 obj = networkService.getObject("product", id); 5 } catch (IOException e) { 6 System.err.println("Error with obj : " + obj.toString()); 7 } 8 return obj; 9 } 2 Object obj = null; 5 } catch (IOException e) { 6 System.err.println("Error with obj : " + obj.toString()); 7 } Faire du code qui marche NullPointerException !
  • 21. 4 account = (BankAccount) service.getProduct(this.name); 5 account.deposit(); 1 public void affiche(BankAccount account, ProductService service) { 2 System.out.println("Bank Account : "+this.name); 3 System.out.println("Autres informations : "); 4 account = (BankAccount) service.getProduct(this.name); 5 account.deposit(); 6 System.out.println(account); 7 System.out.println("=== FIN ==="); 8 9 } Code simple HTTP://EN.WIKIPEDIA.ORG/WIKI/FILE:JEU_DE_MIKADO.JPG
  • 22. 4 account = (BankAccount) service.getProduct(this.name); 5 account.deposit(); 1 public void affiche(BankAccount account, ProductService service) { 2 System.out.println("Bank Account : "+this.name); 3 System.out.println("Autres informations : "); 4 account = (BankAccount) service.getProduct(this.name); 5 account.deposit(); 6 System.out.println(account); 7 System.out.println("=== FIN ==="); 8 9 } Code simple HTTP://EN.WIKIPEDIA.ORG/WIKI/FILE:JEU_DE_MIKADO.JPG
  • 23. 4 account = (BankAccount) service.getProduct(this.name); 5 account.deposit(); 1 public void affiche(BankAccount account, ProductService service) { 2 System.out.println("Bank Account : "+this.name); 3 System.out.println("Autres informations : "); 4 account = (BankAccount) service.getProduct(this.name); 5 account.deposit(); 6 System.out.println(account); 7 System.out.println("=== FIN ==="); 8 9 } Code simple HTTP://EN.WIKIPEDIA.ORG/WIKI/FILE:JEU_DE_MIKADO.JPG
  • 24.
  • 25.
  • 26. C’est compliqué de faire simple un test une évolution
  • 27.
  • 28.
  • 30. Je vous prend dans mon équipe !
  • 39. Toujours faire le test cassant avant le test passant (pour tester le test)
  • 40. TEST UNITAIRE tester la plus petite unité de code possible
  • 41. TEST UNITAIRE tester la plus petite unité de code possible SIMPLE
  • 42. TEST UNITAIRE tester la plus petite unité de code possible SIMPLEFEEDBACK
  • 43. TEST UNITAIRE tester la plus petite unité de code possible SIMPLEFEEDBACKCOÛT
  • 44.
  • 47. 1 @Test 2 public void can_deposit() { 3 bankAccount.setBalance(50); 4 5 boolean result = bankAccount.deposit(1000); 6 7 assertTrue(result); 8 assertEquals(1050, bankAccount.getBalance()); 9 } 3 bankAccount.setBalance(50); Test d’abord !
  • 48. 1 @Test 2 public void can_deposit() { 3 bankAccount.setBalance(50); 4 5 boolean result = bankAccount.deposit(1000); 6 7 assertTrue(result); 8 assertEquals(1050, bankAccount.getBalance()); 9 } 3 bankAccount.setBalance(50); Test d’abord !
  • 49. 5 boolean result = bankAccount.deposit(1000); 1 @Test 2 public void can_deposit() { 3 bankAccount.setBalance(50); 4 5 boolean result = bankAccount.deposit(1000); 6 7 assertTrue(result); 8 assertEquals(1050, bankAccount.getBalance()); 9 } Test d’abord !
  • 50. 1 @Test 2 public void can_deposit() { 3 bankAccount.setBalance(50); 4 5 boolean result = bankAccount.deposit(1000); 6 7 assertTrue(result); 8 assertEquals(1050, bankAccount.getBalance()); 9 } Test d’abord ! 7 assertTrue(result); 8 assertEquals(1050, bankAccount.getBalance());
  • 51. Test d’abord ! 1 boolean deposit(int amount) { 2 return false; 3 }
  • 52. Test d’abord ! 1 boolean deposit(int amount) { 2 return false; 3 }
  • 53. Test d’abord ! 1 boolean deposit(int amount) { 2 bal = bal + amount; 3 return true; 4 }
  • 54. Test d’abord ! 1 boolean deposit(int amount) { 2 bal = bal + amount; 3 return true; 4 }
  • 55. Test d’abord ! 1 @Test 2 public void cant_deposit_with_negative_amount() { 3 bankAccount.setBalance(100); 4 5 boolean result = bankAccount.deposit(-20); 6 7 assertFalse(result); 8 assertEquals(100, bankAccount.getBalance()); 9 }
  • 56. Test d’abord ! 1 @Test 2 public void cant_deposit_with_negative_amount() { 3 bankAccount.setBalance(100); 4 5 boolean result = bankAccount.deposit(-20); 6 7 assertFalse(result); 8 assertEquals(100, bankAccount.getBalance()); 9 } 3 bankAccount.setBalance(100);
  • 57. Test d’abord ! 1 @Test 2 public void cant_deposit_with_negative_amount() { 3 bankAccount.setBalance(100); 4 5 boolean result = bankAccount.deposit(-20); 6 7 assertFalse(result); 8 assertEquals(100, bankAccount.getBalance()); 9 } 5 boolean result = bankAccount.deposit(-20);
  • 58. Test d’abord ! 1 @Test 2 public void cant_deposit_with_negative_amount() { 3 bankAccount.setBalance(100); 4 5 boolean result = bankAccount.deposit(-20); 6 7 assertFalse(result); 8 assertEquals(100, bankAccount.getBalance()); 9 } 7 assertFalse(result); 8 assertEquals(100, bankAccount.getBalance());
  • 59. Test d’abord ! 1 boolean deposit(int amount) { 2 bal = bal + amount; 3 return true; 4 }
  • 60. Test d’abord ! 1 boolean deposit(int amount) { 2 bal = bal + amount; 3 return true; 4 }
  • 61. Test d’abord ! 1 boolean deposit(int amount) { 2 if(amount < 0) { 3 return false; 4 } 5 bal = bal + amount; 6 return true; 7 }
  • 62. Test d’abord ! 1 boolean deposit(int amount) { 2 if(amount < 0) { 3 return false; 4 } 5 bal = bal + amount; 6 return true; 7 }
  • 63. Acteur / Action / Assertion
  • 64. les «3 A» : Acteur/Action/Assertion 1 @Test 2 public void cant_deposit_with_negative_amount() { 3 bankAccount.setBalance(100); 4 5 boolean result = bankAccount.deposit(-20); 6 7 assertFalse(result); 8 assertEquals(100, bankAccount.getBalance()); 9 }
  • 65. 1 @Test 2 public void cant_deposit_with_negative_amount() { 3 bankAccount.setBalance(100); 4 5 boolean result = bankAccount.deposit(-20); 6 7 assertFalse(result); 8 assertEquals(100, bankAccount.getBalance()); 9 } les «3 A» : Acteur/Action/Assertion 3 bankAccount.setBalance(100); Acteur
  • 66. 1 @Test 2 public void cant_deposit_with_negative_amount() { 3 bankAccount.setBalance(100); 4 5 boolean result = bankAccount.deposit(-20); 6 7 assertFalse(result); 8 assertEquals(100, bankAccount.getBalance()); 9 } les «3 A» : Acteur/Action/Assertion 5 boolean result = bankAccount.deposit(-20); Action
  • 67. 1 @Test 2 public void cant_deposit_with_negative_amount() { 3 bankAccount.setBalance(100); 4 5 boolean result = bankAccount.deposit(-20); 6 7 assertFalse(result); 8 assertEquals(100, bankAccount.getBalance()); 9 } les «3 A» : Acteur/Action/Assertion 7 assertFalse(result); 8 assertEquals(100, bankAccount.getBalance()); Assertions
  • 68. KISS
  • 69. KISSKEEP IT SIMPLE (AND STUPID)
  • 70. KISSKEEP IT SIMPLE (AND STUPID)
  • 71. 7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99"); 8 9 // Vérifier. 10 Assert.assertNotNull("Extra non trouvé.", targetDTO); 11 Assert.assertEquals("Les accountId doivent être identiques.", 12 "ABC99", targetDTO.getAccountId()); 1 @Test 2 public void testGetCustomerOK() { 3 4 LOGGER.info("======= testGetCustomerOK starting..."); 5 6 try { 7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99"); 8 9 // Vérifier. 10 Assert.assertNotNull("Extra non trouvé.", targetDTO); 11 Assert.assertEquals("Les accountId doivent être identiques.", 12 "ABC99", targetDTO.getAccountId()); 13 14 } catch (CustomerBusinessException exception) { 15 LOGGER.error("CustomerBusinessException : {}", 16 exception.getCause()); 17 Assert.fail(exception.getMessage()); 18 } catch (UnavailableResourceException exception) { 19 LOGGER.error("UnavailableResourceException : {}", 20 exception.getMessage()); 21 Assert.fail(exception.getMessage()); 22 } catch (UnexpectedException exception) { 23 LOGGER.error("UnexpectedException : {}" + 24 exception.getMessage()); 25 Assert.fail(exception.getMessage()); 26 } catch (Exception exception) { 27 LOGGER.error("CRASH : " + exception.getMessage()); 28 Assert.fail(exception.getMessage()); 29 } 30 31 LOGGER.info("======= testGetCustomerOK done."); 32 }
  • 72. 7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99"); 8 9 // Vérifier. 10 Assert.assertNotNull("Extra non trouvé.", targetDTO); 11 Assert.assertEquals("Les accountId doivent être identiques.", 12 "ABC99", targetDTO.getAccountId()); 1 @Test 2 public void testGetCustomerOK() { 3 4 LOGGER.info("======= testGetCustomerOK starting..."); 5 6 try { 7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99"); 8 9 // Vérifier. 10 Assert.assertNotNull("Extra non trouvé.", targetDTO); 11 Assert.assertEquals("Les accountId doivent être identiques.", 12 "ABC99", targetDTO.getAccountId()); 13 14 } catch (CustomerBusinessException exception) { 15 LOGGER.error("CustomerBusinessException : {}", 16 exception.getCause()); 17 Assert.fail(exception.getMessage()); 18 } catch (UnavailableResourceException exception) { 19 LOGGER.error("UnavailableResourceException : {}", 20 exception.getMessage()); 21 Assert.fail(exception.getMessage()); 22 } catch (UnexpectedException exception) { 23 LOGGER.error("UnexpectedException : {}" + 24 exception.getMessage()); 25 Assert.fail(exception.getMessage()); 26 } catch (Exception exception) { 27 LOGGER.error("CRASH : " + exception.getMessage()); 28 Assert.fail(exception.getMessage()); 29 } 30 31 LOGGER.info("======= testGetCustomerOK done."); 32 }
  • 73. 1 @Test 2 public void testGetCustomerOK() { 3 4 LOGGER.info("======= testGetCustomerOK starting..."); 5 6 try { 7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99"); 8 9 // Vérifier. 10 Assert.assertNotNull("Extra non trouvé.", targetDTO); 11 Assert.assertEquals("Les accountId doivent être identiques.", 12 "ABC99", targetDTO.getAccountId()); 13 14 } catch (CustomerBusinessException exception) { 15 LOGGER.error("CustomerBusinessException : {}", 16 exception.getCause()); 17 Assert.fail(exception.getMessage()); 18 } catch (UnavailableResourceException exception) { 19 LOGGER.error("UnavailableResourceException : {}", 20 exception.getMessage()); 21 Assert.fail(exception.getMessage()); 22 } catch (UnexpectedException exception) { 23 LOGGER.error("UnexpectedException : {}" + 24 exception.getMessage()); 25 Assert.fail(exception.getMessage()); 26 } catch (Exception exception) { 27 LOGGER.error("CRASH : " + exception.getMessage()); 28 Assert.fail(exception.getMessage()); 29 } 30 31 LOGGER.info("======= testGetCustomerOK done."); 32 } 14 } catch (CustomerBusinessException exception) { 15 LOGGER.error("CustomerBusinessException : {}", 16 exception.getCause()); 17 Assert.fail(exception.getMessage()); 18 } catch (UnavailableResourceException exception) { 19 LOGGER.error("UnavailableResourceException : {}", 20 exception.getMessage()); 21 Assert.fail(exception.getMessage()); 22 } catch (UnexpectedException exception) { 23 LOGGER.error("UnexpectedException : {}" + 24 exception.getMessage()); 25 Assert.fail(exception.getMessage()); 26 } catch (Exception exception) { 27 LOGGER.error("CRASH : " + exception.getMessage()); 28 Assert.fail(exception.getMessage()); 29 } 30 31 LOGGER.info("======= testGetCustomerOK done."); BRUIT
  • 74. KISS ! 1 @Test 2 public void can_get_customer() throws Exception { 3 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99"); 4 Assert.assertEquals("Les accountId doivent être identiques.", 5 "ABC99", targetDTO.getAccountId()); 6 }
  • 77. JUNIT + MOCKITO + ASSERTJ
  • 78. JUNIT + MOCKITO + ASSERTJ
  • 79. Mock ? simulacre se fait passer pour ce qu’il n’est pas comportement paramétrable
  • 93. NOUVEAU CODE = NOUVEAU TEST
  • 94. NOUVEAU BUG = NOUVEAU TEST
  • 95. nouveau bug = nouveau test 1 public Object getProduct(String id) { 2 Object obj = null; 3 try { 4 obj = networkService.getObject("product", id); 5 } catch (IOException e) { 6 System.err.println("Error with obj : " + obj.toString()); 7 } 8 return obj; 9 }
  • 96. 1 public Object getProduct(String id) { 2 Object obj = null; 3 try { 4 obj = networkService.getObject("product", id); 5 } catch (IOException e) { 6 System.err.println("Error with obj : " + obj.toString()); 7 } 8 return obj; 9 } nouveau bug = nouveau test 6 System.err.println("Error with obj : " + obj.toString()); LE BUG EST ICI !
  • 97. nouveau bug = nouveau test 1 @Test 2 public void can_return_null_when_ioexception() throws IOException { 3 Mockito.doThrow(IOException.class) 4 .when(networkService).getObject("product", "azerty"); 5 6 Object product = service.getProduct("azerty"); 7 8 assertThat(product).isNull(); 9 }
  • 98. 3 Mockito.doThrow(IOException.class) 4 .when(networkService).getObject("product", "azerty"); 1 @Test 2 public void can_return_null_when_ioexception() throws IOException { 3 Mockito.doThrow(IOException.class) 4 .when(networkService).getObject("product", "azerty"); 5 6 Object product = service.getProduct("azerty"); 7 8 assertThat(product).isNull(); 9 } nouveau bug = nouveau test
  • 99. 1 @Test 2 public void can_return_null_when_ioexception() throws IOException { 3 Mockito.doThrow(IOException.class) 4 .when(networkService).getObject("product", "azerty"); 5 6 Object product = service.getProduct("azerty"); 7 8 assertThat(product).isNull(); 9 } 6 Object product = service.getProduct("azerty"); nouveau bug = nouveau test
  • 100. 8 assertThat(product).isNull(); 1 @Test 2 public void can_return_null_when_ioexception() throws IOException { 3 Mockito.doThrow(IOException.class) 4 .when(networkService).getObject("product", "azerty"); 5 6 Object product = service.getProduct("azerty"); 7 8 assertThat(product).isNull(); 9 } nouveau bug = nouveau test
  • 101. nouveau bug = nouveau test 1 public Object getProduct(String id) { 2 Object obj = null; 3 try { 4 obj = networkService.getObject("product", id); 5 } catch (IOException e) { 6 System.err.println("Error with obj : " + obj.toString()); 7 } 8 return obj; 9 }
  • 102. nouveau bug = nouveau test 1 public Object getProduct(String id) { 2 Object obj = null; 3 try { 4 obj = networkService.getObject("product", id); 5 } catch (IOException e) { 6 System.err.println("Error with obj : " + obj.toString()); 7 } 8 return obj; 9 }
  • 103. 1 public Object getProduct(String id) { 2 Object obj = null; 3 try { 4 obj = networkService.getObject("product", id); 5 } catch (IOException e) { 6 System.err.println("Error with obj : " + obj.toString()); 7 } 8 return obj; 9 } nouveau bug = nouveau test 6 System.err.println("Error with obj : " + obj.toString()); LE BUG EST TOUJOURS ICI !
  • 104. 1 public Object getProduct(String id) { 2 Object obj = null; 3 try { 4 obj = networkService.getObject("product", id); 5 } catch (IOException e) { 6 System.err.println("Error with obj with id: " + id); 7 } 8 return obj; 9 } nouveau bug = nouveau test 6 System.err.println("Error with obj with id: " + id);
  • 105. nouveau bug = nouveau test 1 public Object getProduct(String id) { 2 Object obj = null; 3 try { 4 obj = networkService.getObject("product", id); 5 } catch (IOException e) { 6 System.err.println("Error with obj with id: " + id); 7 } 8 return obj; 9 } 6 System.err.println("Error with obj with id: " + id);
  • 106. Laissez votre câble tranquille
  • 107. TESTER DOIT ÊTRE SIMPLE
  • 108. code complexe 1 /** 2 * 3 * @param xml : document xml représentant le swap 4 * @return objet Swap 5 */ 6 public Swap parse(String xml) { 7 Swap swap = new Swap(); 8 String currency = getNodeValue("/swap/currency", xml); 9 swap.setCurrency(currency); [...] /* beaucoup de code... */ 530 Date d = new Date(); 531 if(test == 1) { 532 if(d.after(spotDate)) { 533 swap.setType("IRS"); 534 } else { 535 swap.setType("CURVE"); 536 } 537 } else if (test == 2) { 538 if(d.after(spotDate)) { 539 swap.setType("IRS"); 540 } else { 541 swap.setType("CURVE"); 542 } 543 } [...] /* encore beaucoup de code... */ 1135 return swap; 1136 }
  • 109. 1 @Test 2 public void can_parse_xml() throws Exception { 3 String xml = "<?xml version="1.0" encoding="UTF-8"?>n" + 4 "<!--n" + 5 "t== Copyright (c) 2002-2005. All rights reserved.n" + 6 "t== Financial Products Markup Language is subject to the FpML public license.n" + 7 "t== A copy of this license is available at http://www.fpml.org/documents/licensen" + 8 "-->n" + 9 "<FpML version="4-2" xmlns="http://www.fpml.org/2005/FpML-4-2" xmlns:xsi="http://www.w3.org/2001/ XMLSchema-instance" xsi:schemaLocation="http://www.fpml.org/2005/FpML-4-2 fpml-main-4-2.xsd" xsi:type= "TradeCashflowsAsserted">n" + 10 "t<header>n" + 11 "tt<messageId messageIdScheme="http://www.example.com/messageId">CEN/2004/01/05/15-38</messageId>n" + 12 "tt<sentBy>ABC</sentBy>n" + 13 "tt<sendTo>DEF</sendTo>n" + 14 "tt<creationTimestamp>2005-01-05T15:38:00-00:00</creationTimestamp>n" + 15 "t</header>n" + 16 "t<asOfDate>2005-01-05T15:00:00-00:00</asOfDate>n" + 17 "t<tradeIdentifyingItems>n" + 18 "tt<partyTradeIdentifier>n" + 19 "ttt<partyReference href="abc"/>n" + 20 "ttt<tradeId tradeIdScheme="http://www.abc.com/tradeId/">trade1abcxxx</tradeId>n" + 21 "tt</partyTradeIdentifier>n" + 22 "tt<partyTradeIdentifier>n" + 23 "ttt<partyReference href="def"/>n" + 24 "ttt<tradeId tradeIdScheme="http://www.def.com/tradeId/">123cds</tradeId>n" + 25 "tt</partyTradeIdentifier>n" + 26 "t</tradeIdentifyingItems>n" + 27 "t<adjustedPaymentDate>2005-01-31</adjustedPaymentDate>n" + 28 "t<netPayment>n" + 29 "tt<identifier netPaymentIdScheme="http://www.centralservice.com/netPaymentId">netPaymentABCDEF001</ identifier>n" + 30 "tt<payerPartyReference href="abc"/>n" + 31 "tt<receiverPartyReference href="def"/>n" + 32 "tt<paymentAmount>n" +
  • 110.
  • 111. code complexe 1 /** 2 * 3 * @param xml : document xml représentant le swap 4 * @return objet Swap 5 */ 6 public Swap parse(String xml) { 7 Swap swap = new Swap(); 8 String currency = getNodeValue("/swap/currency", xml); 9 swap.setCurrency(currency); [...] /* beaucoup de code... */ 530 Date d = new Date(); 531 if(test == 1) { 532 if(d.after(spotDate)) { 533 swap.setType("IRS"); 534 } else { 535 swap.setType("CURVE"); 536 } 537 } else if (test == 2) { 538 if(d.after(spotDate)) { 539 swap.setType("IRS"); 540 } else { 541 swap.setType("CURVE"); 542 } 543 } [...] /* encore beaucoup de code... */ 1135 return swap; 1136 }
  • 112. 1 /** 2 * 3 * @param xml : document xml représentant le swap 4 * @return objet Swap 5 */ 6 public Swap parse(String xml) { 7 Swap swap = new Swap(); 8 String currency = getNodeValue("/swap/currency", xml); 9 swap.setCurrency(currency); [...] /* beaucoup de code... */ 530 Date d = new Date(); 531 if(test == 1) { 532 if(d.after(spotDate)) { 533 swap.setType("IRS"); 534 } else { 535 swap.setType("CURVE"); 536 } 537 } else if (test == 2) { 538 if(d.after(spotDate)) { 539 swap.setType("IRS"); 540 } else { 541 swap.setType("CURVE"); 542 } 543 } [...] /* encore beaucoup de code... */ 1135 return swap; 1136 } code complexe 531 if(test == 1) { 532 if(d.after(spotDate)) { 533 swap.setType("IRS"); 534 } else { 535 swap.setType("CURVE"); 536 } 537 } else if (test == 2) { 538 if(d.after(spotDate)) { 539 swap.setType("IRS"); 540 } else { 541 swap.setType("CURVE"); 542 } 543 } EXTRACT METHOD !
  • 113. code complexe 1 public void updateSwapType(Swap swapToUpdate, Date now, Date spotDate, int test) { 2 if(test == 1) { 3 if(now.after(spotDate)) { 4 swapToUpdate.setType("IRS"); 5 } else { 6 swapToUpdate.setType("CURVE"); 7 } 8 } else if (test == 2) { 9 if(now.after(spotDate)) { 10 swapToUpdate.setType("IRS"); 11 } else { 12 swapToUpdate.setType("CURVE"); 13 } 14 } 15 }
  • 114. code complexe 1 @Test 2 public void can_update_swap_type() throws Exception { 3 Swap swap = new Swap(); 4 Date now = simpleDateFormat.parse("2012-06-15"); 5 Date before = simpleDateFormat.parse("2012-05-05"); 6 service.updateSwapType(swap, now, before, 1); 7 assertEquals("IRS", swap.getType()); 8 }
  • 115. LE CODE DOIT ÊTRE MODULAIRE
  • 116. Singleton 1 public class ProductService { 2 3 private static ProductService instance = new ProductService(); 4 5 private DAOService daoService; 6 7 private ProductService() { 8 System.out.println("ProductService constructor"); 9 daoService = DAOService.getInstance(); 10 } 11 12 public static ProductService getInstance() { 13 return instance; 14 } 15 16 17 18 public Object getProduct(String id) { 19 return daoService.getObject("product", id); 20 } 21 }
  • 117. 1 public class ProductService { 2 3 private static ProductService instance = new ProductService(); 4 5 private DAOService daoService; 6 7 private ProductService() { 8 System.out.println("ProductService constructor"); 9 daoService = DAOService.getInstance(); 10 } 11 12 public static ProductService getInstance() { 13 return instance; 14 } 15 16 17 18 public Object getProduct(String id) { 19 return daoService.getObject("product", id); 20 } 21 } Singleton 3 private static ProductService instance = new ProductService();
  • 118. 1 public class ProductService { 2 3 private static ProductService instance = new ProductService(); 4 5 private DAOService daoService; 6 7 private ProductService() { 8 System.out.println("ProductService constructor"); 9 daoService = DAOService.getInstance(); 10 } 11 12 public static ProductService getInstance() { 13 return instance; 14 } 15 16 17 18 public Object getProduct(String id) { 19 return daoService.getObject("product", id); 20 } 21 } Singleton 7 private ProductService() { 9 daoService = DAOService.getInstance(); 10 }
  • 119. Singleton 1 public class ProductService { 2 3 private static ProductService instance = new ProductService(); 4 5 private DAOService daoService; 6 7 private ProductService() { 8 System.out.println("ProductService constructor"); 9 daoService = DAOService.getInstance(); 10 } 11 12 public static ProductService getInstance() { 13 return instance; 14 } 15 16 17 18 public Object getProduct(String id) { 19 return daoService.getObject("product", id); 20 } 21 }
  • 126. Singleton 1 public void validateSwap(String id) { 2 Swap swap = (Swap) ProductService.getInstance().getProduct(id); 3 swap.updateState("VALIDATE"); 4 ProductService.getInstance().save(swap); 5 }
  • 127. 1 public void validateSwap(String id) { 2 Swap swap = (Swap) ProductService.getInstance().getProduct(id); 3 swap.updateState("VALIDATE"); 4 ProductService.getInstance().save(swap); 5 } Singleton ProductService.getInstance() 4 ProductService.getInstance() COUPLAGE FORT
  • 128. Injection 1 private ProductService productService; 2 3 public void setProductService(ProductService injectedService) { 4 this.productService = injectedService; 5 } 6 7 public void validateSwap(String id) { 8 Swap swap = (Swap) productService.getProduct(id); 9 swap.updateState("VALIDATE"); 10 productService.save(swap); 11 }
  • 129. 1 private ProductService productService; 2 3 public void setProductService(ProductService injectedService) { 4 this.productService = injectedService; 5 } 6 7 public void validateSwap(String id) { 8 Swap swap = (Swap) productService.getProduct(id); 9 swap.updateState("VALIDATE"); 10 productService.save(swap); 11 } Injection 3 public void setProductService(ProductService injectedService) { 4 this.productService = injectedService; 5 } INJECTION
  • 130. 1 private ProductService productService; 2 3 public void setProductService(ProductService injectedService) { 4 this.productService = injectedService; 5 } 6 7 public void validateSwap(String id) { 8 Swap swap = (Swap) productService.getProduct(id); 9 swap.updateState("VALIDATE"); 10 productService.save(swap); 11 } Injection 8 Swap swap = (Swap) productService.getProduct(id); UTILISATION
  • 131. Injection 1 @InjectMocks 2 private BankAccount bankAccount; 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 12 Mockito.doNothing().when(productService).save(swap); 13 14 bankAccount.validateSwap("fakeId"); 15 16 assertEquals("VALIDATE", swap.getState()); 17 }
  • 132. 1 @InjectMocks 2 private BankAccount bankAccount; 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 12 Mockito.doNothing().when(productService).save(swap); 13 14 bankAccount.validateSwap("fakeId"); 15 16 assertEquals("VALIDATE", swap.getState()); 17 } Injection 4 @Mock 5 private ProductService productService; MOCK
  • 133. 1 @InjectMocks 2 private BankAccount bankAccount; 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 12 Mockito.doNothing().when(productService).save(swap); 13 14 bankAccount.validateSwap("fakeId"); 15 16 assertEquals("VALIDATE", swap.getState()); 17 } Injection 1 @InjectMocks 2 private BankAccount bankAccount; INJECTION AUTOMATIQUE DES MOCKS
  • 134. 1 @InjectMocks 2 private BankAccount bankAccount; 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 12 Mockito.doNothing().when(productService).save(swap); 13 14 bankAccount.validateSwap("fakeId"); 15 16 assertEquals("VALIDATE", swap.getState()); 17 } Injection 11 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 12 Mockito.doNothing().when(productService).save(swap);
  • 135. 1 @InjectMocks 2 private BankAccount bankAccount; 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 12 Mockito.doNothing().when(productService).save(swap); 13 14 bankAccount.validateSwap("fakeId"); 15 16 assertEquals("VALIDATE", swap.getState()); 17 } 14 bankAccount.validateSwap("fakeId"); Injection
  • 136. Injection 1 @InjectMocks 2 private BankAccount bankAccount; 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 12 Mockito.doNothing().when(productService).save(swap); 13 14 bankAccount.validateSwap("fakeId"); 15 16 assertEquals("VALIDATE", swap.getState()); 17 } 16 assertEquals("VALIDATE", swap.getState());
  • 139. Sans injecteur ? 1 public void validateSwap(String id) { 2 Swap swap = (Swap) ProductService.getInstance().getProduct(id); 3 swap.updateState("VALIDATE"); 4 ProductService.getInstance().save(swap); 5 }
  • 140. 1 public void validateSwap(String id) { 2 Swap swap = (Swap) ProductService.getInstance().getProduct(id); 3 swap.updateState("VALIDATE"); 4 ProductService.getInstance().save(swap); 5 } Sans injecteur ? ProductService.getInstance() 4 ProductService.getInstance() EXTRACT METHOD !
  • 141. 1 public ProductService getProductService() { 2 return ProductService.getInstance(); 3 } 4 5 public void validateSwap(String id) { 6 Swap swap = (Swap) getProductService().getProduct(id); 7 swap.updateState("VALIDATE"); 8 getProductService().save(swap); 9 } Sans injecteur ? 1 public ProductService getProductService() { 2 return ProductService.getInstance(); 3 } getProductService() 8 getProductService()
  • 142. Sans injecteur ? 1 @Spy 2 private BankAccount bankAccount = new BankAccount("", 23, "", 3); 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(productService).when(bankAccount).getProductService(); 12 13 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 14 Mockito.doNothing().when(productService).save(swap); 15 16 bankAccount.validateSwap("fakeId"); 17 18 assertEquals("VALIDATE", swap.getState()); 19 }
  • 143. 1 @Spy 2 private BankAccount bankAccount = new BankAccount("", 23, "", 3); 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(productService).when(bankAccount).getProductService(); 12 13 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 14 Mockito.doNothing().when(productService).save(swap); 15 16 bankAccount.validateSwap("fakeId"); 17 18 assertEquals("VALIDATE", swap.getState()); 19 } Sans injecteur ? 1 @Spy 2 private BankAccount bankAccount = new BankAccount("", 23, "", 3); REDÉFINITION DES MÉTHODES POSSIBLE
  • 144. 1 @Spy 2 private BankAccount bankAccount = new BankAccount("", 23, "", 3); 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(productService).when(bankAccount).getProductService(); 12 13 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 14 Mockito.doNothing().when(productService).save(swap); 15 16 bankAccount.validateSwap("fakeId"); 17 18 assertEquals("VALIDATE", swap.getState()); 19 } Sans injecteur ? 11 Mockito.doReturn(productService).when(bankAccount).getProductService();
  • 145. 1 @Spy 2 private BankAccount bankAccount = new BankAccount("", 23, "", 3); 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(productService).when(bankAccount).getProductService(); 12 13 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 14 Mockito.doNothing().when(productService).save(swap); 15 16 bankAccount.validateSwap("fakeId"); 17 18 assertEquals("VALIDATE", swap.getState()); 19 } Sans injecteur ? 13 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 14 Mockito.doNothing().when(productService).save(swap);
  • 146. Sans injecteur ? 1 @Spy 2 private BankAccount bankAccount = new BankAccount("", 23, "", 3); 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(productService).when(bankAccount).getProductService(); 12 13 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 14 Mockito.doNothing().when(productService).save(swap); 15 16 bankAccount.validateSwap("fakeId"); 17 18 assertEquals("VALIDATE", swap.getState()); 19 } 16 bankAccount.validateSwap("fakeId");
  • 147. Sans injecteur ? 1 @Spy 2 private BankAccount bankAccount = new BankAccount("", 23, "", 3); 3 4 @Mock 5 private ProductService productService; 6 7 @Test 8 public void can_validate_swap() { 9 Swap swap = new Swap(); 10 11 Mockito.doReturn(productService).when(bankAccount).getProductService(); 12 13 Mockito.doReturn(swap).when(productService).getProduct("fakeId"); 14 Mockito.doNothing().when(productService).save(swap); 15 16 bankAccount.validateSwap("fakeId"); 17 18 assertEquals("VALIDATE", swap.getState()); 19 } 18 assertEquals("VALIDATE", swap.getState());
  • 149. LANCER UN TEST DOIT ÊTRE FACILE
  • 150. Tests dans son IDE ECLIPSE NETBEANS INTELLIJ
  • 151. LE CODE DOIT TOUJOURS ÊTRE DÉPLOYABLE
  • 153. Intégration continue [INFO] --------------------------------------------- [INFO] BUILD SUCCESS [INFO] ---------------------------------------------
  • 155. Intégration continue [INFO] --------------------------------------------- [INFO] BUILD FAILURE [INFO] ---------------------------------------------
  • 156. Intégration continue [INFO] --------------------------------------------- [INFO] BUILD FAILURE [INFO] --------------------------------------------- WORKS ON MY MACHINE
  • 161.
  • 162. AVOIR LA BONNE COUVERTURE
  • 164. 80%DE COUVERTURE DE GETTER/SETTER
  • 166. binomage (pair hero) philosophie différente pour code identique HTTP://WWW.SXC.HU/PHOTO/959091
  • 167. binomage (pair hero) philosophie différente pour code identiqueLES COMMANDES
  • 168. binomage (pair hero) philosophie différente pour code identique LE PLAN DE VOL
  • 174. bref
  • 176. 6 mois plus tard...
  • 177. Bugs 0 22,5 45 67,5 90 Janvier Février Mars Avril Mai Juin Bugs Satisfaction
  • 178. Bugs 0 22,5 45 67,5 90 Janvier Février Mars Avril Mai Juin Bugs Satisfaction
  • 179. Bugs 0 22,5 45 67,5 90 Janvier Février Mars Avril Mai Juin Bugs Satisfaction
  • 180. Bugs 0 22,5 45 67,5 90 Janvier Février Mars Avril Mai Juin Bugs Satisfaction
  • 181. Bugs 0 22,5 45 67,5 90 Janvier Février Mars Avril Mai Juin Bugs Satisfaction
  • 182. Bugs 0 22,5 45 67,5 90 Janvier Février Mars Avril Mai Juin Bugs Satisfaction
  • 183. BRAVO À NOTRE ÉQUIPE DE CHOC !
  • 188. (même si il est «trop» simple)
  • 190. ...AVANT DE GAGNER DES COMPÉTITIONS HTTP://WWW.SXC.HU/PHOTO/1008962
  • 194. It’s Pizza Time !Drink
  • 196. référence jenkins : http://jenkins-ci.org/ assertj : https://github.com/joel-costigliola/assertj mockito : https://code.google.com/p/mockito/ démo : http://parleys.com/play/5148922a0364bc17fc56c85a/about