Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Pratiques avancées de testsNathaniel Richand<br />Scrumday France 2011<br />
Merci aux sponsors du Scrumday !<br />Sponsors Platinum<br />Sponsors Gold<br />Parrainage :<br />
Restons pragmatique !<br />Doit-on :<br />Tester les messages d’exceptions ?<br />Tester les messages de logs ?<br />Conte...
TDD a beaucoup aidé <br />
Certains tests vieillissent mal<br />
Tests illisibleset fragiles<br />Exemple<br />
Constat :<br />TDD peut :<br />devenir un frein, diminuer le rythme<br />Augmenter la rigidité du code<br />
Améliorer la lisibilité<br />
Tip1 : le nom donnel’intention<br />testChoose1()<br />testChoose2()<br />whenSelectNullIItem_ShouldThrowAnException()<br ...
Tip2 : Ne pas masquer les informationsutiles<br />@DataSet<br />publicclassBrokerDAOTestextendsUnitilsTestNG {<br />@Test<...
Tip3 : Masquer tout ce qui est inutile<br />Setup & Teardown<br />Fixture<br />Creation method<br />Creation Builder<br />...
@Test<br />publicvoidgenerateNomDeFichierNacXMLTest(){<br />//Given<br />NacCreatorBOnacCreator = newNacCreatorBO();<br />...
NacCreatorBOnacCreator;<br />@Before<br />publicvoidinit(){<br />nacCreator= newNacCreatorBO();<br />}<br />@Test<br />pub...
@Test<br />publicvoidtestParserIntraday(){<br />    File file = new File("src/test/resources/fr/haramis/service/commons/ut...
@Test<br />publicvoidtestParserIntraday_OK() throws Exception{<br />//Given<br />InputStreamstream = getStreamFromFile("Pl...
//Given<br />Map<Date, BigDecimal> charges = newHashMap<Date, BigDecimal>();<br />charges.put(dateDebut_13_03_2010,<br />n...
//Given<br />Map<Date, BigDecimal> charges = newMapCharges<Date>()<br />  .with(dateDebut_13_03_2010, QUANTITY_1000)<br />...
/**<br /> * Builder pour créer plus facilement des Map<Date, BigDecimal> ou des Map<String, BigDecimal><br /> */<br />priv...
Tip4 : try/catch fail()<br />@Test<br />publicvoidtestFindByStatutAndDate() {<br />OrdreSpotDASdao = newOrdreSpotDAO();<br...
@Test<br />publicvoidtestFindByStatutAndDate() throwsHaramisException{<br />OrdreSpotDASdao = newOrdreSpotDAO();<br />asse...
Tip4 (bis) : if/else fail()<br />if (sd.getTimeRef() == 0) {<br />assertEquals(sd.getPrice(), "301");<br />} else{<br />fa...
assertThat(sd.getTimeRef()).isEqualTo(0);<br />assertEquals(sd.getPrice(), "301");<br />GuardAssert<br />
Tip5 : Simili de toString() dans les assert<br />assertEquals("Compagniedifferente : "+result.getId()+" / "+ result.getNam...
Tip6 : Magic number, magic null<br />//Given<br />Site siteNord = createSite(NORD, 10);<br />Site siteSud = createSite(SUD...
//Given<br />Site siteNord = createSite(NORD, AFFECTATION_NORD);<br />Site siteSud = createSite(SUD, AFFECTATION_SUD);<br ...
Tip7 : Garder la même structure<br />@Test<br />publicvoidcalculTotalTest(){<br />//Given<br />	double[] volumes = {10.245...
@Test<br />publicvoidcalculerDateTest(){<br />//Given<br />	Date date = HaramisDateUtils.creerDateBlanchie(2010, 5, 19);<b...
Tip8 : Faire de belles assertions<br />Ne surtout pas faire : <br />assertFalse(toto == null);<br />assertTrue(list.size()...
File emptyFile = writeFile("emptyFile", "");<br />assertThat(emptyFile).hasSize(0);<br />List<String> names = Arrays.asLis...
for (Companycie : companies) {<br />Assert.assertFalse(cie.getStatus()<br />		.equalsIgnoreCase(ConstantsUtils.SIMPLE_STAT...
Tip9 : Utiliser Spock<br />def"I plus I should equal II"() {<br />given:def calculator = newRomanCalculator()when:    def ...
def"The lowestnumbershould go at the end"() {<br />  setup:<br />defresult = calculator.add(a, b)expect:result == sum  whe...
Faire des tests plus robustes<br />
Tip1 : Pas de duplication<br />Cf. Tip 3 : Masquer tout ce qui est inutile<br />Creation fixture<br />Creation builder<br ...
Tip2 : Tester un comportementà un seulendroit<br />publicString formatResultToCSV(List<Object[]> positionsResultats) throw...
PublicString formatResultToCSV(List<Object[]> positionsResultats) throwsParseException {<br />StringBuildersb = newStringB...
Tip3 : Eviter la réflexion<br />@Test<br />publicvoid testReglesValidationHRM_118_KO() throws Exception {<br />PortfolioMa...
@Test<br />publicvoid testReglesValidationHRM_118_OK() throws Exception {<br />    //Given<br />PortfolioManagerBOportfoli...
Tip4 : Quoi tester?<br />“Bas niveau” : état<br />privatestaticString formatValue(Object removeNull) {<br />if(removeNull ...
“Haut niveau” : comportement<br />public String getPointsHoraires(String dateDeb, String dateFin, String portFolios, Strin...
Bilan<br />Aimez vos tests et ils vous le rendront<br />Les principes “Clean code” s’appliquent également au code de test!...
Ressources<br />http://www.wakaleo.com/blog<br />http://misko.hevery.com/<br />
Merci<br />nrichand@xebia.fr<br />http://blog.xebia.fr<br />
Upcoming SlideShare
Loading in …5
×

2011 nri-pratiques tests-avancees

2,364 views

Published on

Le support de la présentation donné en mars 2011 au ScrumDay

Published in: Technology
  • Be the first to comment

2011 nri-pratiques tests-avancees

  1. 1. Pratiques avancées de testsNathaniel Richand<br />Scrumday France 2011<br />
  2. 2. Merci aux sponsors du Scrumday !<br />Sponsors Platinum<br />Sponsors Gold<br />Parrainage :<br />
  3. 3.
  4. 4. Restons pragmatique !<br />Doit-on :<br />Tester les messages d’exceptions ?<br />Tester les messages de logs ?<br />Contexte<br />
  5. 5. TDD a beaucoup aidé <br />
  6. 6. Certains tests vieillissent mal<br />
  7. 7. Tests illisibleset fragiles<br />Exemple<br />
  8. 8. Constat :<br />TDD peut :<br />devenir un frein, diminuer le rythme<br />Augmenter la rigidité du code<br />
  9. 9. Améliorer la lisibilité<br />
  10. 10. Tip1 : le nom donnel’intention<br />testChoose1()<br />testChoose2()<br />whenSelectNullIItem_ShouldThrowAnException()<br />whenSelectTwoItems_ShouldReturnTheSum()<br />
  11. 11. Tip2 : Ne pas masquer les informationsutiles<br />@DataSet<br />publicclassBrokerDAOTestextendsUnitilsTestNG {<br />@Test<br />publicvoidtestGetNameByClauseInId() {<br />BrokerDASbdao = newBrokerDAO();<br />JpaUnitils.injectEntityManagerInto(bdao);<br /> List<String> brokers = bdao.getNameByClauseInId("in (1)");<br />assertEquals(brokers.size(), 1);<br />assertEquals(brokers.get(0), "Kerviel");<br /> }<br />}<br />WTF?<br />
  12. 12. Tip3 : Masquer tout ce qui est inutile<br />Setup & Teardown<br />Fixture<br />Creation method<br />Creation Builder<br />Static import<br />
  13. 13. @Test<br />publicvoidgenerateNomDeFichierNacXMLTest(){<br />//Given<br />NacCreatorBOnacCreator = newNacCreatorBO();<br />//when<br /> String nomFichier= nacCreator.generateNomDeFichierNacXML (creerDateBlanchie(2010, 01, 02), "123456", creerDateBlanchie(2010, 03, 04), 10);<br />//then<br />assertThat(nomFichier).isEqualTo ("NAC_R_123456RE_020110_10_040310000000.xml");<br />}<br />
  14. 14. NacCreatorBOnacCreator;<br />@Before<br />publicvoidinit(){<br />nacCreator= newNacCreatorBO();<br />}<br />@Test<br />publicvoidgenerateNomDeFichierNacXMLTest(){<br />//when<br /> String nomFichier = nacCreator.generateNomDeFichierNacXML (creerDateBlanchie(2010, 01, 02), "123456", creerDateBlanchie(2010, 03, 04), 10);<br />//then<br />assertThat(nomFichier).isEqualTo ("NAC_R_123456RE_020110_10_040310000000.xml");<br />}<br />
  15. 15. @Test<br />publicvoidtestParserIntraday(){<br /> File file = new File("src/test/resources/fr/haramis/service/commons/util/Planning_Options.xls");<br /> List<IntradaySchedule> listIntradays = null;<br />InputStreamstream = null;<br />try{<br />stream= newFileInputStream(file.getAbsolutePath());<br /> } catch(FileNotFoundException e) {<br />stream= null;<br /> }<br />if(stream != null){<br />try{<br />listIntradays= IntradayParser.parseExcelIntraday(stream, "DIRECT-T01");<br /> } catch(HermesException e) {<br />e.printStackTrace();<br />logger.error(e);<br />Assert.fail();<br /> }<br />logger.info(" ListIntradaysSize() " +listIntradays.size());<br />Assert.assertEquals(8400, listIntradays.size());<br />for(IntradayScheduleintradaySchedule : listIntradays) {<br />Assert.assertEquals(24, intradaySchedule.getIntraday().getIntradaySchedules().size());<br /> }<br /> }<br />}<br />
  16. 16. @Test<br />publicvoidtestParserIntraday_OK() throws Exception{<br />//Given<br />InputStreamstream = getStreamFromFile("Planning_Options.xls");<br />//When<br /> List<IntradaySchedule> listIntradays = IntradayParser.parseExcelIntraday(stream, "DIRECT-T01");<br />//Then<br />assertEquals(8400, listIntradays.size());<br /> for(IntradayScheduleintradaySchedule : listIntradays) {<br />assertEquals(24, intradaySchedule.getIntraday()<br /> .getIntradaySchedules().size());<br /> }<br />}<br />
  17. 17. //Given<br />Map<Date, BigDecimal> charges = newHashMap<Date, BigDecimal>();<br />charges.put(dateDebut_13_03_2010,<br />newBigDecimal(QUANTITY_1000));<br />charges.put(addDaysToDate(dateDebut_13_03_2010, 1),<br />newBigDecimal(QUANTITY_3000));<br />
  18. 18. //Given<br />Map<Date, BigDecimal> charges = newMapCharges<Date>()<br /> .with(dateDebut_13_03_2010, QUANTITY_1000)<br /> .and(addDaysToDate(dateDebut_13_03_2010, 1) QUANTITY_3000)<br /> .build();<br />
  19. 19. /**<br /> * Builder pour créer plus facilement des Map<Date, BigDecimal> ou des Map<String, BigDecimal><br /> */<br />privateclassMapCharges<T> {<br />privateMap<T, BigDecimal> cdcMap = newHashMap<T, BigDecimal>();<br /> publicMapCharges<T> with(T dateDebut, intquantity){<br /> cdcMap.put(dateDebut, newBigDecimal(quantity));<br /> returnthis;<br /> }<br /> publicMapCharges<T> and(T dateDebut, intquantity){<br /> returnwith(dateDebut, quantity);<br /> }<br /> publicMap<T, BigDecimal> build(){<br /> returncdcMap;<br /> }<br />}<br />
  20. 20. Tip4 : try/catch fail()<br />@Test<br />publicvoidtestFindByStatutAndDate() {<br />OrdreSpotDASdao = newOrdreSpotDAO();<br />try{<br />assertEquals(dao.findByDate("01/07/2008", "OK").size(), 2);<br />assertEquals(dao.findByDate("01/07/2008", "KO").size(), 1);<br />} catch (HaramisExceptione) {<br />e.printStackTrace();<br />Assert.fail();<br /> }<br />}<br />
  21. 21. @Test<br />publicvoidtestFindByStatutAndDate() throwsHaramisException{<br />OrdreSpotDASdao = newOrdreSpotDAO();<br />assertEquals(dao.findByDate("01/07/2008", "OK").size(), 2);<br />assertEquals(dao.findByDate("01/07/2008", "KO").size(), 1);<br />}<br />
  22. 22. Tip4 (bis) : if/else fail()<br />if (sd.getTimeRef() == 0) {<br />assertEquals(sd.getPrice(), "301");<br />} else{<br />fail("pas normal");<br />}<br />
  23. 23. assertThat(sd.getTimeRef()).isEqualTo(0);<br />assertEquals(sd.getPrice(), "301");<br />GuardAssert<br />
  24. 24. Tip5 : Simili de toString() dans les assert<br />assertEquals("Compagniedifferente : "+result.getId()+" / "+ result.getName() +" / "+ result.getLocation()<br />, result, expectedCompany);<br />assertThat(result).isEqualTo(expectedCompany);<br />
  25. 25. Tip6 : Magic number, magic null<br />//Given<br />Site siteNord = createSite(NORD, 10);<br />Site siteSud = createSite(SUD, 12);<br />//When<br />intaffectations = dao.selectAffectationsNord(siteNord, siteSud, null); <br />//Then<br />assertThat(affectations).isEqualTo(10);<br />
  26. 26. //Given<br />Site siteNord = createSite(NORD, AFFECTATION_NORD);<br />Site siteSud = createSite(SUD, AFFECTATION_SUD);<br />//When<br />intaffectations = dao.selectAffectationsNord(siteNord, siteSud, SITE_NULL); <br />//Then<br />assertThat(affectations).isEqualTo(AFFECTATION_NORD);<br />
  27. 27. Tip7 : Garder la même structure<br />@Test<br />publicvoidcalculTotalTest(){<br />//Given<br /> double[] volumes = {10.24556, 21, 43};<br /> //When<br /> double total = PositionUtils.calculTotal(UNITE_TEMPS_HORAIRE, volumes);<br /> //Then<br />assertThat(total).isEqualTo(74.24556);<br />}<br />
  28. 28. @Test<br />publicvoidcalculerDateTest(){<br />//Given<br /> Date date = HaramisDateUtils.creerDateBlanchie(2010, 5, 19);<br />//When<br /> String[] datesFormatees = PositionUtils.calculerDates(date, 1, UNITE_TEMPS_HORAIRE, ELECTRICTY);<br />//Then<br />assertThat(datesFormatees).hasSize(2);<br />assertThat(datesFormatees[0]).isEqualTo("19/05/2010 01:00");<br />assertThat(datesFormatees[1]).isEqualTo("19/05/2010 02:00");<br />}<br />
  29. 29. Tip8 : Faire de belles assertions<br />Ne surtout pas faire : <br />assertFalse(toto == null);<br />assertTrue(list.size() == 0);<br />assertEquals(result, null);<br />
  30. 30. File emptyFile = writeFile("emptyFile", "");<br />assertThat(emptyFile).hasSize(0);<br />List<String> names = Arrays.asList("Bob", ”Vince", ”Nat");<br />assertThat(names)<br /> .hasSize(3)<br /> .contains("Vince")<br /> .doesNotHaveDuplicates();<br />String nullString = null;<br />assertThat(nullString).isNull();<br />http://docs.codehaus.org/display/FEST/Fluent+Assertions+Module<br />
  31. 31. for (Companycie : companies) {<br />Assert.assertFalse(cie.getStatus()<br /> .equalsIgnoreCase(ConstantsUtils.SIMPLE_STATUS_ANNULE)<br /> , "Cie " + cie.getId());<br />}<br />assertThat(companies)<br /> .onProperty("status")<br /> .containsOnly(SIMPLE_STATUS_VALIDE);<br />
  32. 32. Tip9 : Utiliser Spock<br />def"I plus I should equal II"() {<br />given:def calculator = newRomanCalculator()when:    def result = calculator.add("I", "I")           then:    result == "II"<br />}<br />http://code.google.com/p/spock/<br />
  33. 33. def"The lowestnumbershould go at the end"() {<br /> setup:<br />defresult = calculator.add(a, b)expect:result == sum  where: a   | b  | sum    "X"  | "I" | "XI"    "I"  | "X" | "XI"    "XX" | "I" | "XXI"    "XX" | "II"| "XXII"    "II" | "XX"| "XXII"  <br />}<br />http://www.wakaleo.com/blog/303-an-introduction-to-spock<br />
  34. 34. Faire des tests plus robustes<br />
  35. 35. Tip1 : Pas de duplication<br />Cf. Tip 3 : Masquer tout ce qui est inutile<br />Creation fixture<br />Creation builder<br />Test Helper<br />Custom assertions<br />
  36. 36. Tip2 : Tester un comportementà un seulendroit<br />publicString formatResultToCSV(List<Object[]> positionsResultats) throwsParseException;<br />privatestatic String[] calculerDeuxDates(Object[] ligne)<br />throwsParseException;<br />publicstatic String[] obtenirVolumes(Object[] ligne);<br />
  37. 37. PublicString formatResultToCSV(List<Object[]> positionsResultats) throwsParseException {<br />StringBuildersb = newStringBuilder();<br /> for(Object[] ligne : positionsResultats) {<br />String[] twoDates = calculerDeuxDates(ligne);<br />String[] newLine = new String[ligne.length -1];<br />newLine[0] = twoDates[0];<br />newLine[1] = twoDates[1];<br />String[] volumes = PositionUtils.obtenirVolumes(ligne);<br />System.arraycopy(volumes, 0, newLine, 2, volumes.length);<br />for(String elementLigne : newLine) {<br />sb.append(elementLigne+"|");<br />}<br />}<br />returnsb.toString();<br />}<br />
  38. 38. Tip3 : Eviter la réflexion<br />@Test<br />publicvoid testReglesValidationHRM_118_KO() throws Exception {<br />PortfolioManagerBOportfolioManagerBO = newPortfolioManagerBO();<br />Method reglesValidationHRM118 = null;<br />PortfolioFormportfolioForm = newPortfolioForm();<br />portfolioManagerBO.setPortfolioForm(portfolioForm);<br />reglesValidationHRM118 = ReflectHelper.getPrivateMethod(portfolioManagerBO, "reglesValidationHRM118");<br /> reglesValidationHRM118.setAccessible(true);<br /> reglesValidationHRM118.invoke(portfolioManagerBO);<br />assertFalse(portfolioForm.isMessageAVisible());<br />assertFalse(portfolioForm.isPopupVisible());<br />}<br />
  39. 39. @Test<br />publicvoid testReglesValidationHRM_118_OK() throws Exception {<br /> //Given<br />PortfolioManagerBOportfolioManagerBO = newPortfolioManagerBO();<br />PortfolioFormportfolioForm = newPortfolioForm();<br />portfolioManagerBO.setPortfolioForm(portfolioForm);<br /> //When<br /> portfolioManagerBO.reglesValidationHRM118();<br /> //Then<br />assertFalse(portfolioForm.isMessageAVisible());<br />assertFalse(portfolioForm.isPopupVisible());<br />}<br />
  40. 40. Tip4 : Quoi tester?<br />“Bas niveau” : état<br />privatestaticString formatValue(Object removeNull) {<br />if(removeNull == null) {<br /> return"";<br /> } else {<br /> returnremoveNull.toString();<br /> }<br />}<br />
  41. 41. “Haut niveau” : comportement<br />public String getPointsHoraires(String dateDeb, String dateFin, String portFolios, String password) {<br />passwordChecker.checkPassword(password);<br /> List<Long> listIdPortfolio = convertPortfoliosIdToLong(portFolios);<br /> List<Object[]> pointsResultats = executeCalculPointsPortefeuille(<br />dateDeb, dateFin, listIdPortfolio);<br /> String pointsCSV= formatResultToCSV(pointsResultats);<br />returnpointsCSV;<br />}<br />
  42. 42. Bilan<br />Aimez vos tests et ils vous le rendront<br />Les principes “Clean code” s’appliquent également au code de test!<br />
  43. 43. Ressources<br />http://www.wakaleo.com/blog<br />http://misko.hevery.com/<br />
  44. 44. Merci<br />nrichand@xebia.fr<br />http://blog.xebia.fr<br />

×