Your SlideShare is downloading. ×
Tests unitaires mock_kesako_20130516
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Tests unitaires mock_kesako_20130516

1,323

Published on

Vous subissez les régressions à chaque livraison ? Vous ne voyez pas l’intérêt des tests unitaires car ils ne servent qu’à tester des additions ? Les tests ne sont pas applicables à votre projet car …

Vous subissez les régressions à chaque livraison ? Vous ne voyez pas l’intérêt des tests unitaires car ils ne servent qu’à tester des additions ? Les tests ne sont pas applicables à votre projet car il est trop complexe ? Si c’est le cas, suivez David dans la quête du Test Driven Development. Vous rencontrerez pléthore d’ennemies contre lesquels vous aurez à combattre : bugs, complexité, code statique, couplage fort. Ils essaieront de vous barrer la route, mais heureusement, vous pourrez compter sur vos alliés jUnit, Mockito, refactoring et injection/dépendance.
David finira la soirée par une démonstration pratique sur un exercice de refactoring.

Published in: Technology, Economy & Finance
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
1,323
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
36
Comments
0
Likes
0
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. 16 mai 13Test unitaire ?Mock ? TDD ?Kezako ?1
  • 2. Bienvenue !
  • 3. ❤=+
  • 4. réseaux sociauxProchaines conférences : http://soat.frtwitter : @soatgroup / @soatexpertsjavaslideshares : http://fr.slideshare.net/soatexpertAller plus loin : http://blog.soat.fr
  • 5. Test unitaire ? Mock ? TDD ? Kezako ?en finir avec les régressions par David Wursteisen16 MAI 2013
  • 6. Nouveau client !
  • 7. Nouveau projet !
  • 8. HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGLEGACY CODE
  • 9. 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;}
  • 10. La documentation explique le code1 /**2 *3 * @param xml : document xml représentant le swap4 * @return objet Swap5 */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 }1000LIGNES !
  • 11. La documentation a raison1 /**2 * Always returns true.3 */4 public boolean isAvailable() {5 return false;6 }
  • 12. La documentation a raison1 /**2 * Always returns true.3 */4 public boolean isAvailable() {5 return false;6 }WTF ?!?
  • 13. La documentation n’est plusfiableune aideutile
  • 14. 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
  • 15. 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
  • 16. 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 marcheNullPointerException !
  • 17. 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 ===");89 }Code simpleHTTP://EN.WIKIPEDIA.ORG/WIKI/FILE:JEU_DE_MIKADO.JPG
  • 18. 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 ===");89 }Code simpleHTTP://EN.WIKIPEDIA.ORG/WIKI/FILE:JEU_DE_MIKADO.JPG
  • 19. 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 ===");89 }Code simpleHTTP://EN.WIKIPEDIA.ORG/WIKI/FILE:JEU_DE_MIKADO.JPG
  • 20. C’est compliqué de fairesimpleun testune évolution
  • 21. Bonne nouvelle !
  • 22. Je vous prend dans mon équipe !
  • 23. HTTP://WWW.SXC.HU/PROFILE/HOTBLACKCOMMENT VAT’ON POUVOIRS’EN SORTIR ?
  • 24. HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGTEST DRIVEN DEVELOPMENT
  • 25. PRINCIPE DE BASE
  • 26. Ecrituredu test
  • 27. Lancementdu testEcrituredu test
  • 28. Lancementdu testCorrection del’implémentationEcrituredu testKO
  • 29. Lancementdu testCorrection del’implémentationEcrituredu testFinKOOK
  • 30. Lancementdu testCorrection del’implémentationEcrituredu testFinKOOKREFACTOR
  • 31. Toujours faire le test cassant avantle test passant(pour tester le test)
  • 32. TEST UNITAIREtester la plus petite unité de code possible
  • 33. TEST UNITAIREtester la plus petite unité de code possibleSIMPLE
  • 34. TEST UNITAIREtester la plus petite unité de code possibleSIMPLEFEEDBACK
  • 35. TEST UNITAIREtester la plus petite unité de code possibleSIMPLEFEEDBACKCOÛT
  • 36. $400MILLIONS
  • 37. EXEMPLE
  • 38. 1 @Test2 public void can_deposit() {3 bankAccount.setBalance(50);45 boolean result = bankAccount.deposit(1000);67 assertTrue(result);8 assertEquals(1050, bankAccount.getBalance());9 }3 bankAccount.setBalance(50);Test d’abord !
  • 39. 1 @Test2 public void can_deposit() {3 bankAccount.setBalance(50);45 boolean result = bankAccount.deposit(1000);67 assertTrue(result);8 assertEquals(1050, bankAccount.getBalance());9 }3 bankAccount.setBalance(50);Test d’abord !
  • 40. 5 boolean result = bankAccount.deposit(1000);1 @Test2 public void can_deposit() {3 bankAccount.setBalance(50);45 boolean result = bankAccount.deposit(1000);67 assertTrue(result);8 assertEquals(1050, bankAccount.getBalance());9 }Test d’abord !
  • 41. 1 @Test2 public void can_deposit() {3 bankAccount.setBalance(50);45 boolean result = bankAccount.deposit(1000);67 assertTrue(result);8 assertEquals(1050, bankAccount.getBalance());9 }Test d’abord !7 assertTrue(result);8 assertEquals(1050, bankAccount.getBalance());
  • 42. Test d’abord !1 boolean deposit(int amount) {2 return false;3 }
  • 43. Test d’abord !1 boolean deposit(int amount) {2 return false;3 }
  • 44. Test d’abord !1 boolean deposit(int amount) {2 bal = bal + amount;3 return true;4 }
  • 45. Test d’abord !1 boolean deposit(int amount) {2 bal = bal + amount;3 return true;4 }
  • 46. Test d’abord !1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.deposit(-20);67 assertFalse(result);8 assertEquals(100, bankAccount.getBalance());9 }
  • 47. Test d’abord !1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.deposit(-20);67 assertFalse(result);8 assertEquals(100, bankAccount.getBalance());9 }3 bankAccount.setBalance(100);
  • 48. Test d’abord !1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.deposit(-20);67 assertFalse(result);8 assertEquals(100, bankAccount.getBalance());9 }5 boolean result = bankAccount.deposit(-20);
  • 49. Test d’abord !1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.deposit(-20);67 assertFalse(result);8 assertEquals(100, bankAccount.getBalance());9 }7 assertFalse(result);8 assertEquals(100, bankAccount.getBalance());
  • 50. Test d’abord !1 boolean deposit(int amount) {2 bal = bal + amount;3 return true;4 }
  • 51. Test d’abord !1 boolean deposit(int amount) {2 bal = bal + amount;3 return true;4 }
  • 52. Test d’abord !1 boolean deposit(int amount) {2 if(amount < 0) {3 return false;4 }5 bal = bal + amount;6 return true;7 }
  • 53. Test d’abord !1 boolean deposit(int amount) {2 if(amount < 0) {3 return false;4 }5 bal = bal + amount;6 return true;7 }
  • 54. Acteur / Action / Assertion
  • 55. les «3 A» : Acteur/Action/Assertion1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.deposit(-20);67 assertFalse(result);8 assertEquals(100, bankAccount.getBalance());9 }
  • 56. 1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.deposit(-20);67 assertFalse(result);8 assertEquals(100, bankAccount.getBalance());9 }les «3 A» : Acteur/Action/Assertion3 bankAccount.setBalance(100);Acteur
  • 57. 1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.deposit(-20);67 assertFalse(result);8 assertEquals(100, bankAccount.getBalance());9 }les «3 A» : Acteur/Action/Assertion5 boolean result = bankAccount.deposit(-20);Action
  • 58. 1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.deposit(-20);67 assertFalse(result);8 assertEquals(100, bankAccount.getBalance());9 }les «3 A» : Acteur/Action/Assertion7 assertFalse(result);8 assertEquals(100, bankAccount.getBalance());Assertions
  • 59. KISS
  • 60. KISSKEEP IT SIMPLE (AND STUPID)
  • 61. KISSKEEP IT SIMPLE (AND STUPID)
  • 62. 7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");89 // Vérifier.10 Assert.assertNotNull("Extra non trouvé.", targetDTO);11 Assert.assertEquals("Les accountId doivent être identiques.",12 "ABC99", targetDTO.getAccountId());1 @Test2 public void testGetCustomerOK() {34 LOGGER.info("======= testGetCustomerOK starting...");56 try {7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");89 // Vérifier.10 Assert.assertNotNull("Extra non trouvé.", targetDTO);11 Assert.assertEquals("Les accountId doivent être identiques.",12 "ABC99", targetDTO.getAccountId());1314 } 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 }3031 LOGGER.info("======= testGetCustomerOK done.");32 }
  • 63. 7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");89 // Vérifier.10 Assert.assertNotNull("Extra non trouvé.", targetDTO);11 Assert.assertEquals("Les accountId doivent être identiques.",12 "ABC99", targetDTO.getAccountId());1 @Test2 public void testGetCustomerOK() {34 LOGGER.info("======= testGetCustomerOK starting...");56 try {7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");89 // Vérifier.10 Assert.assertNotNull("Extra non trouvé.", targetDTO);11 Assert.assertEquals("Les accountId doivent être identiques.",12 "ABC99", targetDTO.getAccountId());1314 } 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 }3031 LOGGER.info("======= testGetCustomerOK done.");32 }
  • 64. 1 @Test2 public void testGetCustomerOK() {34 LOGGER.info("======= testGetCustomerOK starting...");56 try {7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");89 // Vérifier.10 Assert.assertNotNull("Extra non trouvé.", targetDTO);11 Assert.assertEquals("Les accountId doivent être identiques.",12 "ABC99", targetDTO.getAccountId());1314 } 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 }3031 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 }3031 LOGGER.info("======= testGetCustomerOK done.");BRUIT
  • 65. KISS !1 @Test2 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 }
  • 66. HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGEN PRATIQUE
  • 67. VENIR ARMÉ
  • 68. JUNIT + MOCKITO + ASSERTJ
  • 69. JUNIT + MOCKITO + ASSERTJ
  • 70. Mock ?simulacrese fait passer pour ce qu’iln’est pascomportementparamétrable
  • 71. MOCKITO
  • 72. doReturn(new BankAccount()).when(daoService).getObject("product", "id");
  • 73. doReturn(new BankAccount()).when(daoService).getObject("product", "id");doReturn(new BankAccount())
  • 74. doReturn(new BankAccount()).when(daoService).getObject("product", "id");when(daoService)
  • 75. doReturn(new BankAccount()).when(daoService).getObject("product", "id");getObject("product", "id");
  • 76. doThrow(IOException.class).when(daoService).getObject("product", "id");
  • 77. doThrow(IOException.class).when(daoService).getObject("product", "id");doThrow(IOException.class)
  • 78. doThrow(IOException.class).when(daoService).getObject("product", "id");when(daoService)
  • 79. doThrow(IOException.class).when(daoService).getObject("product", "id");getObject("product", "id");
  • 80. ASSERTJ
  • 81. assertThat(age).isGreaterThan(5);
  • 82. assertThat(myList).containsExactly("MONAD42", "META18")
  • 83. assertThat(negotation).isBooked();
  • 84. NOUVEAU CODE = NOUVEAU TEST
  • 85. NOUVEAU BUG = NOUVEAU TEST
  • 86. nouveau bug = nouveau test1 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 }
  • 87. 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 test6 System.err.println("Error with obj : " + obj.toString());LE BUG EST ICI !
  • 88. nouveau bug = nouveau test1 @Test2 public void can_return_null_when_ioexception() throws IOException {3 Mockito.doThrow(IOException.class)4 .when(networkService).getObject("product", "azerty");56 Object product = service.getProduct("azerty");78 assertThat(product).isNull();9 }
  • 89. 3 Mockito.doThrow(IOException.class)4 .when(networkService).getObject("product", "azerty");1 @Test2 public void can_return_null_when_ioexception() throws IOException {3 Mockito.doThrow(IOException.class)4 .when(networkService).getObject("product", "azerty");56 Object product = service.getProduct("azerty");78 assertThat(product).isNull();9 }nouveau bug = nouveau test
  • 90. 1 @Test2 public void can_return_null_when_ioexception() throws IOException {3 Mockito.doThrow(IOException.class)4 .when(networkService).getObject("product", "azerty");56 Object product = service.getProduct("azerty");78 assertThat(product).isNull();9 }6 Object product = service.getProduct("azerty");nouveau bug = nouveau test
  • 91. 8 assertThat(product).isNull();1 @Test2 public void can_return_null_when_ioexception() throws IOException {3 Mockito.doThrow(IOException.class)4 .when(networkService).getObject("product", "azerty");56 Object product = service.getProduct("azerty");78 assertThat(product).isNull();9 }nouveau bug = nouveau test
  • 92. nouveau bug = nouveau test1 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 }
  • 93. nouveau bug = nouveau test1 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 }
  • 94. 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 test6 System.err.println("Error with obj : " + obj.toString());LE BUG EST TOUJOURS ICI !
  • 95. 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 test6 System.err.println("Error with obj with id: " + id);
  • 96. nouveau bug = nouveau test1 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);
  • 97. Laissez votre câble tranquille
  • 98. TESTER DOIT ÊTRE SIMPLE
  • 99. code complexe1 /**2 *3 * @param xml : document xml représentant le swap4 * @return objet Swap5 */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 }
  • 100. 1 @Test2 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" +
  • 101. code complexe1 /**2 *3 * @param xml : document xml représentant le swap4 * @return objet Swap5 */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 }
  • 102. 1 /**2 *3 * @param xml : document xml représentant le swap4 * @return objet Swap5 */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 complexe531 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 !
  • 103. code complexe1 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 }
  • 104. code complexe1 @Test2 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 }
  • 105. LE CODE DOIT ÊTRE MODULAIRE
  • 106. Singleton1 public class ProductService {23 private static ProductService instance = new ProductService();45 private DAOService daoService;67 private ProductService() {8 System.out.println("ProductService constructor");9 daoService = DAOService.getInstance();10 }1112 public static ProductService getInstance() {13 return instance;14 }15161718 public Object getProduct(String id) {19 return daoService.getObject("product", id);20 }21 }
  • 107. 1 public class ProductService {23 private static ProductService instance = new ProductService();45 private DAOService daoService;67 private ProductService() {8 System.out.println("ProductService constructor");9 daoService = DAOService.getInstance();10 }1112 public static ProductService getInstance() {13 return instance;14 }15161718 public Object getProduct(String id) {19 return daoService.getObject("product", id);20 }21 }Singleton3 private static ProductService instance = new ProductService();
  • 108. 1 public class ProductService {23 private static ProductService instance = new ProductService();45 private DAOService daoService;67 private ProductService() {8 System.out.println("ProductService constructor");9 daoService = DAOService.getInstance();10 }1112 public static ProductService getInstance() {13 return instance;14 }15161718 public Object getProduct(String id) {19 return daoService.getObject("product", id);20 }21 }Singleton7 private ProductService() {9 daoService = DAOService.getInstance();10 }
  • 109. Singleton1 public class ProductService {23 private static ProductService instance = new ProductService();45 private DAOService daoService;67 private ProductService() {8 System.out.println("ProductService constructor");9 daoService = DAOService.getInstance();10 }1112 public static ProductService getInstance() {13 return instance;14 }15161718 public Object getProduct(String id) {19 return daoService.getObject("product", id);20 }21 }
  • 110. SingletonCode
  • 111. SingletonCode ProductService
  • 112. SingletonCode ProductService DAOService
  • 113. SingletonCode ProductService DAOService
  • 114. SingletonCode ProductService DAOService
  • 115. SingletonCode ProductService DAOServiceMockProductService
  • 116. Singleton1 public void validateSwap(String id) {2 Swap swap = (Swap) ProductService.getInstance().getProduct(id);3 swap.updateState("VALIDATE");4 ProductService.getInstance().save(swap);5 }
  • 117. 1 public void validateSwap(String id) {2 Swap swap = (Swap) ProductService.getInstance().getProduct(id);3 swap.updateState("VALIDATE");4 ProductService.getInstance().save(swap);5 }SingletonProductService.getInstance()4 ProductService.getInstance()COUPLAGE FORT
  • 118. Injection1 private ProductService productService;23 public void setProductService(ProductService injectedService) {4 this.productService = injectedService;5 }67 public void validateSwap(String id) {8 Swap swap = (Swap) productService.getProduct(id);9 swap.updateState("VALIDATE");10 productService.save(swap);11 }
  • 119. 1 private ProductService productService;23 public void setProductService(ProductService injectedService) {4 this.productService = injectedService;5 }67 public void validateSwap(String id) {8 Swap swap = (Swap) productService.getProduct(id);9 swap.updateState("VALIDATE");10 productService.save(swap);11 }Injection3 public void setProductService(ProductService injectedService) {4 this.productService = injectedService;5 }INJECTION
  • 120. 1 private ProductService productService;23 public void setProductService(ProductService injectedService) {4 this.productService = injectedService;5 }67 public void validateSwap(String id) {8 Swap swap = (Swap) productService.getProduct(id);9 swap.updateState("VALIDATE");10 productService.save(swap);11 }Injection8 Swap swap = (Swap) productService.getProduct(id);UTILISATION
  • 121. Injection1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(swap).when(productService).getProduct("fakeId");12 Mockito.doNothing().when(productService).save(swap);1314 bankAccount.validateSwap("fakeId");1516 assertEquals("VALIDATE", swap.getState());17 }
  • 122. 1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(swap).when(productService).getProduct("fakeId");12 Mockito.doNothing().when(productService).save(swap);1314 bankAccount.validateSwap("fakeId");1516 assertEquals("VALIDATE", swap.getState());17 }Injection4 @Mock5 private ProductService productService;MOCK
  • 123. 1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(swap).when(productService).getProduct("fakeId");12 Mockito.doNothing().when(productService).save(swap);1314 bankAccount.validateSwap("fakeId");1516 assertEquals("VALIDATE", swap.getState());17 }Injection1 @InjectMocks2 private BankAccount bankAccount;INJECTION AUTOMATIQUEDES MOCKS
  • 124. 1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(swap).when(productService).getProduct("fakeId");12 Mockito.doNothing().when(productService).save(swap);1314 bankAccount.validateSwap("fakeId");1516 assertEquals("VALIDATE", swap.getState());17 }Injection11 Mockito.doReturn(swap).when(productService).getProduct("fakeId");12 Mockito.doNothing().when(productService).save(swap);
  • 125. 1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(swap).when(productService).getProduct("fakeId");12 Mockito.doNothing().when(productService).save(swap);1314 bankAccount.validateSwap("fakeId");1516 assertEquals("VALIDATE", swap.getState());17 }14 bankAccount.validateSwap("fakeId");Injection
  • 126. Injection1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(swap).when(productService).getProduct("fakeId");12 Mockito.doNothing().when(productService).save(swap);1314 bankAccount.validateSwap("fakeId");1516 assertEquals("VALIDATE", swap.getState());17 }16 assertEquals("VALIDATE", swap.getState());
  • 127. YODA (C) DISNEY
  • 128. UTILISE L’INJECTION,LUKEYODA (C) DISNEY
  • 129. 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 }
  • 130. 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 !
  • 131. 1 public ProductService getProductService() {2 return ProductService.getInstance();3 }45 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()
  • 132. Sans injecteur ?1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(productService).when(bankAccount).getProductService();1213 Mockito.doReturn(swap).when(productService).getProduct("fakeId");14 Mockito.doNothing().when(productService).save(swap);1516 bankAccount.validateSwap("fakeId");1718 assertEquals("VALIDATE", swap.getState());19 }
  • 133. 1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(productService).when(bankAccount).getProductService();1213 Mockito.doReturn(swap).when(productService).getProduct("fakeId");14 Mockito.doNothing().when(productService).save(swap);1516 bankAccount.validateSwap("fakeId");1718 assertEquals("VALIDATE", swap.getState());19 }Sans injecteur ?1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);REDÉFINITION DES MÉTHODESPOSSIBLE
  • 134. 1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(productService).when(bankAccount).getProductService();1213 Mockito.doReturn(swap).when(productService).getProduct("fakeId");14 Mockito.doNothing().when(productService).save(swap);1516 bankAccount.validateSwap("fakeId");1718 assertEquals("VALIDATE", swap.getState());19 }Sans injecteur ?11 Mockito.doReturn(productService).when(bankAccount).getProductService();
  • 135. 1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(productService).when(bankAccount).getProductService();1213 Mockito.doReturn(swap).when(productService).getProduct("fakeId");14 Mockito.doNothing().when(productService).save(swap);1516 bankAccount.validateSwap("fakeId");1718 assertEquals("VALIDATE", swap.getState());19 }Sans injecteur ?13 Mockito.doReturn(swap).when(productService).getProduct("fakeId");14 Mockito.doNothing().when(productService).save(swap);
  • 136. Sans injecteur ?1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(productService).when(bankAccount).getProductService();1213 Mockito.doReturn(swap).when(productService).getProduct("fakeId");14 Mockito.doNothing().when(productService).save(swap);1516 bankAccount.validateSwap("fakeId");1718 assertEquals("VALIDATE", swap.getState());19 }16 bankAccount.validateSwap("fakeId");
  • 137. Sans injecteur ?1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService productService;67 @Test8 public void can_validate_swap() {9 Swap swap = new Swap();1011 Mockito.doReturn(productService).when(bankAccount).getProductService();1213 Mockito.doReturn(swap).when(productService).getProduct("fakeId");14 Mockito.doNothing().when(productService).save(swap);1516 bankAccount.validateSwap("fakeId");1718 assertEquals("VALIDATE", swap.getState());19 }18 assertEquals("VALIDATE", swap.getState());
  • 138. Avertissement
  • 139. LANCER UN TEST DOIT ÊTRE FACILE
  • 140. Tests dans son IDEECLIPSENETBEANSINTELLIJ
  • 141. LE CODE DOIT TOUJOURSÊTRE DÉPLOYABLE
  • 142. Intégration continuemvn install
  • 143. Intégration continue[INFO] ---------------------------------------------[INFO] BUILD SUCCESS[INFO] ---------------------------------------------
  • 144. Intégration continuemvn install
  • 145. Intégration continue[INFO] ---------------------------------------------[INFO] BUILD FAILURE[INFO] ---------------------------------------------
  • 146. Intégration continue[INFO] ---------------------------------------------[INFO] BUILD FAILURE[INFO] ---------------------------------------------WORKS ONMYMACHINE
  • 147. Intégration continueDéclenchementd’un build
  • 148. Intégration continueDéclenchementd’un buildCompilation
  • 149. Intégration continueDéclenchementd’un buildCompilation Test
  • 150. Intégration continueDéclenchementd’un buildCompilation TestDéploiementAnalyse de code
  • 151. AVOIR LA BONNE COUVERTURE
  • 152. 80%DE COUVERTURE DE CODE
  • 153. 80%DE COUVERTURE DE GETTER/SETTER
  • 154. TRAVAILLER EN BINÔME
  • 155. binomage (pair hero)philosophie différente pour code identiqueHTTP://WWW.SXC.HU/PHOTO/959091
  • 156. binomage (pair hero)philosophie différente pour code identiqueLES COMMANDES
  • 157. binomage (pair hero)philosophie différente pour code identiqueLE PLAN DE VOL
  • 158. Ping Pong
  • 159. J’écris le test
  • 160. Il écrit l’implémentation
  • 161. J’écris le test
  • 162. Il écrit l’implémentation
  • 163. bref
  • 164. j’ai binômé
  • 165. 6 mois plus tard...
  • 166. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  • 167. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  • 168. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  • 169. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  • 170. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  • 171. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  • 172. BRAVO À NOTRE ÉQUIPE DE CHOC !
  • 173. (POUR RÉSUMER)
  • 174. Installez Jenkins
  • 175. Automatisez votre build
  • 176. Écrivez votre 1er test
  • 177. (même si il est «trop» simple)
  • 178. HTTP://WWW.SXC.HU/PHOTO/664214IL FAUT APPRENDREÀ NAGER...
  • 179. ...AVANT DE GAGNERDES COMPÉTITIONSHTTP://WWW.SXC.HU/PHOTO/1008962
  • 180. ( DEMO )
  • 181. HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGQUESTIONS ?
  • 182. Merci !
  • 183. It’s Pizza Time !Drink
  • 184. @DWURSTEISEN
  • 185. référencejenkins : http://jenkins-ci.org/assertj : https://github.com/joel-costigliola/assertjmockito : https://code.google.com/p/mockito/démo : http://parleys.com/play/5148922a0364bc17fc56c85a/about

×