16 mai 13Test unitaire ?Mock ? TDD ?Kezako ?1
Bienvenue !
❤=+
réseaux sociauxProchaines conférences : http://soat.frtwitter : @soatgroup / @soatexpertsjavaslideshares : http://fr.slide...
Test unitaire ? Mock ? TDD ? Kezako ?en finir avec les régressions par David Wursteisen16 MAI 2013
Nouveau client !
Nouveau projet !
HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGLEGACY CODE
La documentation explique le code/**** @param xml : document xml représentant le swap* @return objet Swap*/public Swap par...
La documentation explique le code1 /**2 *3 * @param xml : document xml représentant le swap4 * @return objet Swap5 */6 pub...
La documentation a raison1 /**2 * Always returns true.3 */4 public boolean isAvailable() {5 return false;6 }
La documentation a raison1 /**2 * Always returns true.3 */4 public boolean isAvailable() {5 return false;6 }WTF ?!?
La documentation n’est plusfiableune aideutile
4 obj = networkService.getObject("product", id);1 public Object getProduct(String id) {2 Object obj = null;3 try {4 obj = ...
4 obj = networkService.getObject("product", id);1 public Object getProduct(String id) {2 Object obj = null;3 try {4 obj = ...
1 public Object getProduct(String id) {2 Object obj = null;3 try {4 obj = networkService.getObject("product", id);5 } catc...
4 account = (BankAccount) service.getProduct(this.name);5 account.deposit();1 public void affiche(BankAccount account, Pro...
4 account = (BankAccount) service.getProduct(this.name);5 account.deposit();1 public void affiche(BankAccount account, Pro...
4 account = (BankAccount) service.getProduct(this.name);5 account.deposit();1 public void affiche(BankAccount account, Pro...
C’est compliqué de fairesimpleun testune évolution
Bonne nouvelle !
Je vous prend dans mon équipe !
HTTP://WWW.SXC.HU/PROFILE/HOTBLACKCOMMENT VAT’ON POUVOIRS’EN SORTIR ?
HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGTEST DRIVEN DEV...
PRINCIPE DE BASE
Ecrituredu test
Lancementdu testEcrituredu test
Lancementdu testCorrection del’implémentationEcrituredu testKO
Lancementdu testCorrection del’implémentationEcrituredu testFinKOOK
Lancementdu testCorrection del’implémentationEcrituredu testFinKOOKREFACTOR
Toujours faire le test cassant avantle test passant(pour tester le test)
TEST UNITAIREtester la plus petite unité de code possible
TEST UNITAIREtester la plus petite unité de code possibleSIMPLE
TEST UNITAIREtester la plus petite unité de code possibleSIMPLEFEEDBACK
TEST UNITAIREtester la plus petite unité de code possibleSIMPLEFEEDBACKCOÛT
$400MILLIONS
EXEMPLE
1 @Test2 public void can_deposit() {3 bankAccount.setBalance(50);45 boolean result = bankAccount.deposit(1000);67 assertTr...
1 @Test2 public void can_deposit() {3 bankAccount.setBalance(50);45 boolean result = bankAccount.deposit(1000);67 assertTr...
5 boolean result = bankAccount.deposit(1000);1 @Test2 public void can_deposit() {3 bankAccount.setBalance(50);45 boolean r...
1 @Test2 public void can_deposit() {3 bankAccount.setBalance(50);45 boolean result = bankAccount.deposit(1000);67 assertTr...
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 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = ...
Test d’abord !1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = ...
Test d’abord !1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = ...
Test d’abord !1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = ...
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/Assertion1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100)...
1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.de...
1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.de...
1 @Test2 public void cant_deposit_with_negative_amount() {3 bankAccount.setBalance(100);45 boolean result = bankAccount.de...
KISS
KISSKEEP IT SIMPLE (AND STUPID)
KISSKEEP IT SIMPLE (AND STUPID)
7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");89 // Vérifier.10 Assert.assertNotNull("Extra non trouvé...
7 CustomerDTO targetDTO = this.serviceImpl.getCustomer("ABC99");89 // Vérifier.10 Assert.assertNotNull("Extra non trouvé...
1 @Test2 public void testGetCustomerOK() {34 LOGGER.info("======= testGetCustomerOK starting...");56 try {7 CustomerDTO ta...
KISS !1 @Test2 public void can_get_customer() throws Exception {3 CustomerDTO targetDTO = this.serviceImpl.getCustomer("AB...
HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGEN PRATIQUE
VENIR ARMÉ
JUNIT + MOCKITO + ASSERTJ
JUNIT + MOCKITO + ASSERTJ
Mock ?simulacrese fait passer pour ce qu’iln’est pascomportementparamé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 test1 public Object getProduct(String id) {2 Object obj = null;3 try {4 obj = networkService.getObje...
1 public Object getProduct(String id) {2 Object obj = null;3 try {4 obj = networkService.getObject("product", id);5 } catc...
nouveau bug = nouveau test1 @Test2 public void can_return_null_when_ioexception() throws IOException {3 Mockito.doThrow(IO...
3 Mockito.doThrow(IOException.class)4 .when(networkService).getObject("product", "azerty");1 @Test2 public void can_return...
1 @Test2 public void can_return_null_when_ioexception() throws IOException {3 Mockito.doThrow(IOException.class)4 .when(ne...
8 assertThat(product).isNull();1 @Test2 public void can_return_null_when_ioexception() throws IOException {3 Mockito.doThr...
nouveau bug = nouveau test1 public Object getProduct(String id) {2 Object obj = null;3 try {4 obj = networkService.getObje...
nouveau bug = nouveau test1 public Object getProduct(String id) {2 Object obj = null;3 try {4 obj = networkService.getObje...
1 public Object getProduct(String id) {2 Object obj = null;3 try {4 obj = networkService.getObject("product", id);5 } catc...
1 public Object getProduct(String id) {2 Object obj = null;3 try {4 obj = networkService.getObject("product", id);5 } catc...
nouveau bug = nouveau test1 public Object getProduct(String id) {2 Object obj = null;3 try {4 obj = networkService.getObje...
Laissez votre câble tranquille
TESTER DOIT ÊTRE SIMPLE
code complexe1 /**2 *3 * @param xml : document xml représentant le swap4 * @return objet Swap5 */6 public Swap parse(Strin...
1 @Test2 public void can_parse_xml() throws Exception {3 String xml = "<?xml version="1.0" encoding="UTF-8"?>n" +4 "<!--n"...
code complexe1 /**2 *3 * @param xml : document xml représentant le swap4 * @return objet Swap5 */6 public Swap parse(Strin...
1 /**2 *3 * @param xml : document xml représentant le swap4 * @return objet Swap5 */6 public Swap parse(String xml) {7 Swa...
code complexe1 public void updateSwapType(Swap swapToUpdate, Date now, Date spotDate, int test) {2 if(test == 1) {3 if(now...
code complexe1 @Test2 public void can_update_swap_type() throws Exception {3 Swap swap = new Swap();4 Date now = simpleDat...
LE CODE DOIT ÊTRE MODULAIRE
Singleton1 public class ProductService {23 private static ProductService instance = new ProductService();45 private DAOSer...
1 public class ProductService {23 private static ProductService instance = new ProductService();45 private DAOService daoS...
1 public class ProductService {23 private static ProductService instance = new ProductService();45 private DAOService daoS...
Singleton1 public class ProductService {23 private static ProductService instance = new ProductService();45 private DAOSer...
SingletonCode
SingletonCode ProductService
SingletonCode ProductService DAOService
SingletonCode ProductService DAOService
SingletonCode ProductService DAOService
SingletonCode ProductService DAOServiceMockProductService
Singleton1 public void validateSwap(String id) {2 Swap swap = (Swap) ProductService.getInstance().getProduct(id);3 swap.up...
1 public void validateSwap(String id) {2 Swap swap = (Swap) ProductService.getInstance().getProduct(id);3 swap.updateState...
Injection1 private ProductService productService;23 public void setProductService(ProductService injectedService) {4 this....
1 private ProductService productService;23 public void setProductService(ProductService injectedService) {4 this.productSe...
1 private ProductService productService;23 public void setProductService(ProductService injectedService) {4 this.productSe...
Injection1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public ...
1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public void can_...
1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public void can_...
1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public void can_...
1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public void can_...
Injection1 @InjectMocks2 private BankAccount bankAccount;34 @Mock5 private ProductService productService;67 @Test8 public ...
YODA (C) DISNEY
UTILISE L’INJECTION,LUKEYODA (C) DISNEY
Sans injecteur ?1 public void validateSwap(String id) {2 Swap swap = (Swap) ProductService.getInstance().getProduct(id);3 ...
1 public void validateSwap(String id) {2 Swap swap = (Swap) ProductService.getInstance().getProduct(id);3 swap.updateState...
1 public ProductService getProductService() {2 return ProductService.getInstance();3 }45 public void validateSwap(String i...
Sans injecteur ?1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService ...
1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService productService;6...
1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService productService;6...
1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService productService;6...
Sans injecteur ?1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService ...
Sans injecteur ?1 @Spy2 private BankAccount bankAccount = new BankAccount("", 23, "", 3);34 @Mock5 private ProductService ...
Avertissement
LANCER UN TEST DOIT ÊTRE FACILE
Tests dans son IDEECLIPSENETBEANSINTELLIJ
LE CODE DOIT TOUJOURSÊTRE DÉPLOYABLE
Intégration continuemvn install
Intégration continue[INFO] ---------------------------------------------[INFO] BUILD SUCCESS[INFO] -----------------------...
Intégration continuemvn install
Intégration continue[INFO] ---------------------------------------------[INFO] BUILD FAILURE[INFO] -----------------------...
Intégration continue[INFO] ---------------------------------------------[INFO] BUILD FAILURE[INFO] -----------------------...
Intégration continueDéclenchementd’un build
Intégration continueDéclenchementd’un buildCompilation
Intégration continueDéclenchementd’un buildCompilation Test
Intégration continueDéclenchementd’un buildCompilation TestDéploiementAnalyse 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 identiqueHTTP://WWW.SXC.HU/PHOTO/959091
binomage (pair hero)philosophie différente pour code identiqueLES COMMANDES
binomage (pair hero)philosophie différente pour code identiqueLE 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...
Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs 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/664214IL FAUT APPRENDREÀ NAGER...
...AVANT DE GAGNERDES COMPÉTITIONSHTTP://WWW.SXC.HU/PHOTO/1008962
( DEMO )
HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGQUESTIONS ?
Merci !
It’s Pizza Time !Drink
@DWURSTEISEN
référencejenkins : http://jenkins-ci.org/assertj : https://github.com/joel-costigliola/assertjmockito : https://code.googl...
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Tests unitaires mock_kesako_20130516
Upcoming SlideShare
Loading in …5
×

Tests unitaires mock_kesako_20130516

1,895 views

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 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,895
On SlideShare
0
From Embeds
0
Number of Embeds
200
Actions
Shares
0
Downloads
46
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Tests unitaires mock_kesako_20130516

  1. 1. 16 mai 13Test unitaire ?Mock ? TDD ?Kezako ?1
  2. 2. Bienvenue !
  3. 3. ❤=+
  4. 4. réseaux sociauxProchaines conférences : http://soat.frtwitter : @soatgroup / @soatexpertsjavaslideshares : http://fr.slideshare.net/soatexpertAller plus loin : http://blog.soat.fr
  5. 5. Test unitaire ? Mock ? TDD ? Kezako ?en finir avec les régressions par David Wursteisen16 MAI 2013
  6. 6. Nouveau client !
  7. 7. Nouveau projet !
  8. 8. HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGLEGACY CODE
  9. 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. 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. 11. La documentation a raison1 /**2 * Always returns true.3 */4 public boolean isAvailable() {5 return false;6 }
  12. 12. La documentation a raison1 /**2 * Always returns true.3 */4 public boolean isAvailable() {5 return false;6 }WTF ?!?
  13. 13. La documentation n’est plusfiableune aideutile
  14. 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. 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. 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. 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. 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. 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. 20. C’est compliqué de fairesimpleun testune évolution
  21. 21. Bonne nouvelle !
  22. 22. Je vous prend dans mon équipe !
  23. 23. HTTP://WWW.SXC.HU/PROFILE/HOTBLACKCOMMENT VAT’ON POUVOIRS’EN SORTIR ?
  24. 24. HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGTEST DRIVEN DEVELOPMENT
  25. 25. PRINCIPE DE BASE
  26. 26. Ecrituredu test
  27. 27. Lancementdu testEcrituredu test
  28. 28. Lancementdu testCorrection del’implémentationEcrituredu testKO
  29. 29. Lancementdu testCorrection del’implémentationEcrituredu testFinKOOK
  30. 30. Lancementdu testCorrection del’implémentationEcrituredu testFinKOOKREFACTOR
  31. 31. Toujours faire le test cassant avantle test passant(pour tester le test)
  32. 32. TEST UNITAIREtester la plus petite unité de code possible
  33. 33. TEST UNITAIREtester la plus petite unité de code possibleSIMPLE
  34. 34. TEST UNITAIREtester la plus petite unité de code possibleSIMPLEFEEDBACK
  35. 35. TEST UNITAIREtester la plus petite unité de code possibleSIMPLEFEEDBACKCOÛT
  36. 36. $400MILLIONS
  37. 37. EXEMPLE
  38. 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. 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. 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. 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. 42. Test d’abord !1 boolean deposit(int amount) {2 return false;3 }
  43. 43. Test d’abord !1 boolean deposit(int amount) {2 return false;3 }
  44. 44. Test d’abord !1 boolean deposit(int amount) {2 bal = bal + amount;3 return true;4 }
  45. 45. Test d’abord !1 boolean deposit(int amount) {2 bal = bal + amount;3 return true;4 }
  46. 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. 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. 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. 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. 50. Test d’abord !1 boolean deposit(int amount) {2 bal = bal + amount;3 return true;4 }
  51. 51. Test d’abord !1 boolean deposit(int amount) {2 bal = bal + amount;3 return true;4 }
  52. 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. 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. 54. Acteur / Action / Assertion
  55. 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. 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. 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. 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. 59. KISS
  60. 60. KISSKEEP IT SIMPLE (AND STUPID)
  61. 61. KISSKEEP IT SIMPLE (AND STUPID)
  62. 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. 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. 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. 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. 66. HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGEN PRATIQUE
  67. 67. VENIR ARMÉ
  68. 68. JUNIT + MOCKITO + ASSERTJ
  69. 69. JUNIT + MOCKITO + ASSERTJ
  70. 70. Mock ?simulacrese fait passer pour ce qu’iln’est pascomportementparamétrable
  71. 71. MOCKITO
  72. 72. doReturn(new BankAccount()).when(daoService).getObject("product", "id");
  73. 73. doReturn(new BankAccount()).when(daoService).getObject("product", "id");doReturn(new BankAccount())
  74. 74. doReturn(new BankAccount()).when(daoService).getObject("product", "id");when(daoService)
  75. 75. doReturn(new BankAccount()).when(daoService).getObject("product", "id");getObject("product", "id");
  76. 76. doThrow(IOException.class).when(daoService).getObject("product", "id");
  77. 77. doThrow(IOException.class).when(daoService).getObject("product", "id");doThrow(IOException.class)
  78. 78. doThrow(IOException.class).when(daoService).getObject("product", "id");when(daoService)
  79. 79. doThrow(IOException.class).when(daoService).getObject("product", "id");getObject("product", "id");
  80. 80. ASSERTJ
  81. 81. assertThat(age).isGreaterThan(5);
  82. 82. assertThat(myList).containsExactly("MONAD42", "META18")
  83. 83. assertThat(negotation).isBooked();
  84. 84. NOUVEAU CODE = NOUVEAU TEST
  85. 85. NOUVEAU BUG = NOUVEAU TEST
  86. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 97. Laissez votre câble tranquille
  98. 98. TESTER DOIT ÊTRE SIMPLE
  99. 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. 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. 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. 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. 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. 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. 105. LE CODE DOIT ÊTRE MODULAIRE
  106. 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. 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. 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. 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. 110. SingletonCode
  111. 111. SingletonCode ProductService
  112. 112. SingletonCode ProductService DAOService
  113. 113. SingletonCode ProductService DAOService
  114. 114. SingletonCode ProductService DAOService
  115. 115. SingletonCode ProductService DAOServiceMockProductService
  116. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 127. YODA (C) DISNEY
  128. 128. UTILISE L’INJECTION,LUKEYODA (C) DISNEY
  129. 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. 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. 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. 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. 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. 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. 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. 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. 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. 138. Avertissement
  139. 139. LANCER UN TEST DOIT ÊTRE FACILE
  140. 140. Tests dans son IDEECLIPSENETBEANSINTELLIJ
  141. 141. LE CODE DOIT TOUJOURSÊTRE DÉPLOYABLE
  142. 142. Intégration continuemvn install
  143. 143. Intégration continue[INFO] ---------------------------------------------[INFO] BUILD SUCCESS[INFO] ---------------------------------------------
  144. 144. Intégration continuemvn install
  145. 145. Intégration continue[INFO] ---------------------------------------------[INFO] BUILD FAILURE[INFO] ---------------------------------------------
  146. 146. Intégration continue[INFO] ---------------------------------------------[INFO] BUILD FAILURE[INFO] ---------------------------------------------WORKS ONMYMACHINE
  147. 147. Intégration continueDéclenchementd’un build
  148. 148. Intégration continueDéclenchementd’un buildCompilation
  149. 149. Intégration continueDéclenchementd’un buildCompilation Test
  150. 150. Intégration continueDéclenchementd’un buildCompilation TestDéploiementAnalyse de code
  151. 151. AVOIR LA BONNE COUVERTURE
  152. 152. 80%DE COUVERTURE DE CODE
  153. 153. 80%DE COUVERTURE DE GETTER/SETTER
  154. 154. TRAVAILLER EN BINÔME
  155. 155. binomage (pair hero)philosophie différente pour code identiqueHTTP://WWW.SXC.HU/PHOTO/959091
  156. 156. binomage (pair hero)philosophie différente pour code identiqueLES COMMANDES
  157. 157. binomage (pair hero)philosophie différente pour code identiqueLE PLAN DE VOL
  158. 158. Ping Pong
  159. 159. J’écris le test
  160. 160. Il écrit l’implémentation
  161. 161. J’écris le test
  162. 162. Il écrit l’implémentation
  163. 163. bref
  164. 164. j’ai binômé
  165. 165. 6 mois plus tard...
  166. 166. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  167. 167. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  168. 168. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  169. 169. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  170. 170. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  171. 171. Bugs022,54567,590Janvier Février Mars Avril Mai JuinBugs Satisfaction
  172. 172. BRAVO À NOTRE ÉQUIPE DE CHOC !
  173. 173. (POUR RÉSUMER)
  174. 174. Installez Jenkins
  175. 175. Automatisez votre build
  176. 176. Écrivez votre 1er test
  177. 177. (même si il est «trop» simple)
  178. 178. HTTP://WWW.SXC.HU/PHOTO/664214IL FAUT APPRENDREÀ NAGER...
  179. 179. ...AVANT DE GAGNERDES COMPÉTITIONSHTTP://WWW.SXC.HU/PHOTO/1008962
  180. 180. ( DEMO )
  181. 181. HTTP://UPLOAD.WIKIMEDIA.ORG/WIKIPEDIA/COMMONS/THUMB/6/69/HUMAN_EVOLUTION.SVG/1000PX-HUMAN_EVOLUTION.SVG.PNGQUESTIONS ?
  182. 182. Merci !
  183. 183. It’s Pizza Time !Drink
  184. 184. @DWURSTEISEN
  185. 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

×