44
Pratiques avancées de tests Nathaniel Richand Scrum day France 2011

2011 nri-pratiques tests-avancees

Embed Size (px)

DESCRIPTION

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

Citation preview

Page 1: 2011 nri-pratiques tests-avancees

Pratiques avancées de testsNathaniel Richand

Scrum day France 2011

Page 2: 2011 nri-pratiques tests-avancees

Merci aux sponsors du Scrum day !

Sponsors Platinum

Sponsors Gold

Parrainage :

Page 3: 2011 nri-pratiques tests-avancees
Page 4: 2011 nri-pratiques tests-avancees

Restons pragmatique !

Doit-on :• Tester les messages d’exceptions ?• Tester les messages de logs ?

Contexte

Page 5: 2011 nri-pratiques tests-avancees

TDD A BEAUCOUP AIDÉ

Page 6: 2011 nri-pratiques tests-avancees

Certains tests vieillissent mal

Page 7: 2011 nri-pratiques tests-avancees

Tests illisibles et fragiles

Exemple

Page 8: 2011 nri-pratiques tests-avancees

Constat :

TDD peut :• devenir un frein, diminuer le rythme• Augmenter la rigidité du code

Page 9: 2011 nri-pratiques tests-avancees

AMÉLIORER LA LISIBILITÉ

Page 10: 2011 nri-pratiques tests-avancees

Tip1 : le nom donne l’intention

• testChoose1()• testChoose2()

• whenSelectNullIItem_ShouldThrowAnException()• whenSelectTwoItems_ShouldReturnTheSum()

Page 11: 2011 nri-pratiques tests-avancees

Tip2 : Ne pas masquer les informations utiles

@DataSetpublic class BrokerDAOTest extends UnitilsTestNG {

@Test public void testGetNameByClauseInId() { BrokerDAS bdao = new BrokerDAO(); JpaUnitils.injectEntityManagerInto(bdao);

List<String> brokers = bdao.getNameByClauseInId("in (1)"); assertEquals(brokers.size(), 1); assertEquals(brokers.get(0), "Kerviel"); }}

WTF?

Page 12: 2011 nri-pratiques tests-avancees

Tip3 : Masquer tout ce qui est inutile

• Setup & Teardown• Fixture• Creation method• Creation Builder• Static import

Page 13: 2011 nri-pratiques tests-avancees

@Testpublic void generateNomDeFichierNacXMLTest(){ //Given NacCreatorBO nacCreator = new NacCreatorBO();

//when String nomFichier = nacCreator.generateNomDeFichierNacXML(creerDateBlanchie(2010, 01, 02), "123456", creerDateBlanchie(2010, 03, 04), 10); //then assertThat(nomFichier).isEqualTo("NAC_R_123456RE_020110_10_040310000000.xml");}

Page 14: 2011 nri-pratiques tests-avancees

NacCreatorBO nacCreator;

@Beforepublic void init(){ nacCreator = new NacCreatorBO();}

@Testpublic void generateNomDeFichierNacXMLTest(){ //when String nomFichier = nacCreator.generateNomDeFichierNacXML

(creerDateBlanchie(2010, 01, 02), "123456", creerDateBlanchie(2010, 03, 04), 10); //then assertThat(nomFichier).isEqualTo("NAC_R_123456RE_020110_10_040310000000.xml");}

Page 15: 2011 nri-pratiques tests-avancees

@Testpublic void testParserIntraday(){ File file = new File("src/test/resources/fr/haramis/service/commons/util/Planning_Options.xls"); List<IntradaySchedule> listIntradays = null; InputStream stream = null; try { stream = new FileInputStream(file.getAbsolutePath()); } catch (FileNotFoundException e) { stream = null; }

if (stream != null){ try { listIntradays = IntradayParser.parseExcelIntraday(stream, "DIRECT-T01"); } catch (HermesException e) { e.printStackTrace(); logger.error(e);

Assert.fail(); } logger.info(" ListIntradaysSize() " +listIntradays.size()); Assert.assertEquals(8400, listIntradays.size());

for (IntradaySchedule intradaySchedule : listIntradays) { Assert.assertEquals(24, intradaySchedule.getIntraday().getIntradaySchedules().size()); } }}

Page 16: 2011 nri-pratiques tests-avancees

@Testpublic void testParserIntraday_OK() throws Exception{ //Given InputStream stream = getStreamFromFile("Planning_Options.xls");

//When List<IntradaySchedule> listIntradays = IntradayParser.parseExcelIntraday(stream, "DIRECT-T01");

//Then assertEquals(8400, listIntradays.size()); for (IntradaySchedule intradaySchedule : listIntradays) { assertEquals(24, intradaySchedule.getIntraday() .getIntradaySchedules().size()); }}

Page 17: 2011 nri-pratiques tests-avancees

//GivenMap<Date, BigDecimal> charges = new

HashMap<Date, BigDecimal>();

charges.put(dateDebut_13_03_2010,new BigDecimal(QUANTITY_1000));

charges.put(addDaysToDate(dateDebut_13_03_2010, 1),

new BigDecimal(QUANTITY_3000));

Page 18: 2011 nri-pratiques tests-avancees

//GivenMap<Date, BigDecimal> charges = new

MapCharges<Date>() .with(dateDebut_13_03_2010, QUANTITY_1000) .and(addDaysToDate(dateDebut_13_03_2010, 1)

QUANTITY_3000) .build();

Page 19: 2011 nri-pratiques tests-avancees

/** * Builder pour créer plus facilement des Map<Date, BigDecimal> ou des

Map<String, BigDecimal> */private class MapCharges<T> { private Map<T, BigDecimal> cdcMap = new HashMap<T,

BigDecimal>();

public MapCharges<T> with(T dateDebut, int quantity){ cdcMap.put(dateDebut, new BigDecimal(quantity)); return this; } public MapCharges<T> and(T dateDebut, int quantity){ return with(dateDebut, quantity); } public Map<T, BigDecimal> build(){ return cdcMap; }}

Page 20: 2011 nri-pratiques tests-avancees

Tip4 : try/catch fail()@Testpublic void testFindByStatutAndDate() { OrdreSpotDAS dao = new OrdreSpotDAO();

try { assertEquals(dao.findByDate("01/07/2008", "OK").size(), 2); assertEquals(dao.findByDate("01/07/2008", "KO").size(), 1); } catch (HaramisException e) { e.printStackTrace(); Assert.fail(); }}

Page 21: 2011 nri-pratiques tests-avancees

@Testpublic void testFindByStatutAndDate() throws HaramisException{ OrdreSpotDAS dao = new OrdreSpotDAO();

assertEquals(dao.findByDate("01/07/2008", "OK").size(), 2); assertEquals(dao.findByDate("01/07/2008", "KO").size(), 1);}

Page 22: 2011 nri-pratiques tests-avancees

Tip4 (bis) : if/else fail()

if (sd.getTimeRef() == 0) {assertEquals(sd.getPrice(), "301");

} else {fail("pas normal");

}

Page 23: 2011 nri-pratiques tests-avancees

assertThat(sd.getTimeRef()).isEqualTo(0);

assertEquals(sd.getPrice(), "301");

Guard Assert

Page 24: 2011 nri-pratiques tests-avancees

Tip5 : Simili de toString() dans les assert

assertEquals("Compagnie differente : "+result.getId()+" / "+ result.getName() +" / "+ result.getLocation()

, result, expectedCompany);

assertThat(result).isEqualTo(expectedCompany);

Page 25: 2011 nri-pratiques tests-avancees

Tip6 : Magic number, magic null

//GivenSite siteNord = createSite(NORD, 10);Site siteSud = createSite(SUD, 12);

//Whenint affectations = dao.selectAffectationsNord(siteNord, siteSud, null);

//ThenassertThat(affectations).isEqualTo(10);

Page 26: 2011 nri-pratiques tests-avancees

//GivenSite siteNord = createSite(NORD, AFFECTATION_NORD);Site siteSud = createSite(SUD, AFFECTATION_SUD);

//Whenint affectations = dao.selectAffectationsNord(siteNord, siteSud, SITE_NULL);

//ThenassertThat(affectations).isEqualTo(AFFECTATION_NORD);

Page 27: 2011 nri-pratiques tests-avancees

Tip7 : Garder la même structure@Testpublic void calculTotalTest(){

//Givendouble[] volumes = {10.24556, 21, 43};

//Whendouble total = PositionUtils.calculTotal(UNITE_TEMPS_HORAIRE, volumes);

//ThenassertThat(total).isEqualTo(74.24556);

}

Page 28: 2011 nri-pratiques tests-avancees

@Testpublic void calculerDateTest(){

//GivenDate date = HaramisDateUtils.creerDateBlanchie(2010, 5, 19);

//WhenString[] datesFormatees = PositionUtils.calculerDates(date, 1, UNITE_TEMPS_HORAIRE, ELECTRICTY);

//ThenassertThat(datesFormatees).hasSize(2);assertThat(datesFormatees[0]).isEqualTo("19/05/2010 01:00");assertThat(datesFormatees[1]).isEqualTo("19/05/2010 02:00");

}

Page 29: 2011 nri-pratiques tests-avancees

Tip8 : Faire de belles assertions

• Ne surtout pas faire : – assertFalse(toto == null);– assertTrue(list.size() == 0);– assertEquals(result, null);

Page 30: 2011 nri-pratiques tests-avancees

File emptyFile = writeFile("emptyFile", "");assertThat(emptyFile).hasSize(0);

List<String> names = Arrays.asList("Bob", ”Vince", ”Nat");assertThat(names) .hasSize(3) .contains("Vince") .doesNotHaveDuplicates();

String nullString = null;assertThat(nullString).isNull();

http://docs.codehaus.org/display/FEST/Fluent+Assertions+Module

Page 31: 2011 nri-pratiques tests-avancees

for (Company cie : companies) {Assert.assertFalse(cie.getStatus()

.equalsIgnoreCase(ConstantsUtils.SIMPLE_STATUS_ANNULE), "Cie " + cie.getId());

}

assertThat(companies).onProperty("status").containsOnly(SIMPLE_STATUS_VALIDE);

Page 32: 2011 nri-pratiques tests-avancees

Tip9 : Utiliser Spock

def "I plus I should equal II"() { given:

def calculator = new RomanCalculator()when:    def result = calculator.add("I", "I")           then:    result == "II"

}

http://code.google.com/p/spock/

Page 33: 2011 nri-pratiques tests-avancees

def "The lowest number should go at the end"() { setup: def result = 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"  

}

http://www.wakaleo.com/blog/303-an-introduction-to-spock

Page 34: 2011 nri-pratiques tests-avancees

FAIRE DES TESTS PLUS ROBUSTES

Page 35: 2011 nri-pratiques tests-avancees

Tip1 : Pas de duplication

• Cf. Tip 3 : Masquer tout ce qui est inutile– Creation fixture– Creation builder

• Test Helper• Custom assertions

Page 36: 2011 nri-pratiques tests-avancees

Tip2 : Tester un comportement à un seul endroit

public String formatResultToCSV(List<Object[]> positionsResultats) throws ParseException;

private static String[] calculerDeuxDates(Object[] ligne)throws ParseException;

public static String[] obtenirVolumes(Object[] ligne);

Page 37: 2011 nri-pratiques tests-avancees

Public String formatResultToCSV(List<Object[]> positionsResultats) throws ParseException { StringBuilder sb = new StringBuilder(); for (Object[] ligne : positionsResultats) { String[] twoDates = calculerDeuxDates(ligne);

String[] newLine = new String[ligne.length -1]; newLine[0] = twoDates[0]; newLine[1] = twoDates[1]; String[] volumes = PositionUtils.obtenirVolumes(ligne); System.arraycopy(volumes, 0, newLine, 2, volumes.length); for (String elementLigne : newLine) { sb.append(elementLigne+"|"); } } return sb.toString();}

Page 38: 2011 nri-pratiques tests-avancees

Tip3 : Eviter la réflexion@Testpublic void testReglesValidationHRM_118_KO() throws Exception { PortfolioManagerBO portfolioManagerBO = new PortfolioManagerBO(); Method reglesValidationHRM118 = null; PortfolioForm portfolioForm = new PortfolioForm(); portfolioManagerBO.setPortfolioForm(portfolioForm);

reglesValidationHRM118 = ReflectHelper.getPrivateMethod(portfolioManagerBO, "reglesValidationHRM118");

reglesValidationHRM118.setAccessible(true); reglesValidationHRM118.invoke(portfolioManagerBO);

assertFalse(portfolioForm.isMessageAVisible()); assertFalse(portfolioForm.isPopupVisible());}

Page 39: 2011 nri-pratiques tests-avancees

@Testpublic void testReglesValidationHRM_118_OK() throws Exception { //Given PortfolioManagerBO portfolioManagerBO = new PortfolioManagerBO(); PortfolioForm portfolioForm = new PortfolioForm(); portfolioManagerBO.setPortfolioForm(portfolioForm);

//When portfolioManagerBO.reglesValidationHRM118();

//Then assertFalse(portfolioForm.isMessageAVisible()); assertFalse(portfolioForm.isPopupVisible());}

Page 40: 2011 nri-pratiques tests-avancees

Tip4 : Quoi tester?

“Bas niveau” : état

private static String formatValue(Object removeNull) { if (removeNull == null) { return ""; } else { return removeNull.toString(); }}

Page 41: 2011 nri-pratiques tests-avancees

“Haut niveau” : comportement

public String getPointsHoraires(String dateDeb, String dateFin, String portFolios, String password) { passwordChecker.checkPassword(password);

List<Long> listIdPortfolio = convertPortfoliosIdToLong(portFolios);

List<Object[]> pointsResultats = executeCalculPointsPortefeuille(

dateDeb, dateFin, listIdPortfolio);

String pointsCSV = formatResultToCSV(pointsResultats);

return pointsCSV ;}

Page 42: 2011 nri-pratiques tests-avancees

Bilan

• Aimez vos tests et ils vous le rendront

• Les principes “Clean code” s’appliquent également au code de test!

Page 43: 2011 nri-pratiques tests-avancees

Ressources

• http://www.wakaleo.com/blog• http://misko.hevery.com/