2011 nri-pratiques tests-avancees
-
Upload
nathaniel-richand -
Category
Technology
-
view
2.069 -
download
0
description
Transcript of 2011 nri-pratiques tests-avancees
Pratiques avancées de testsNathaniel Richand
Scrum day France 2011
Merci aux sponsors du Scrum day !
Sponsors Platinum
Sponsors Gold
Parrainage :
Restons pragmatique !
Doit-on :• Tester les messages d’exceptions ?• Tester les messages de logs ?
Contexte
TDD A BEAUCOUP AIDÉ
Certains tests vieillissent mal
Tests illisibles et fragiles
Exemple
Constat :
TDD peut :• devenir un frein, diminuer le rythme• Augmenter la rigidité du code
AMÉLIORER LA LISIBILITÉ
Tip1 : le nom donne l’intention
• testChoose1()• testChoose2()
• whenSelectNullIItem_ShouldThrowAnException()• whenSelectTwoItems_ShouldReturnTheSum()
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?
Tip3 : Masquer tout ce qui est inutile
• Setup & Teardown• Fixture• Creation method• Creation Builder• Static import
@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");}
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");}
@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()); } }}
@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()); }}
//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));
//GivenMap<Date, BigDecimal> charges = new
MapCharges<Date>() .with(dateDebut_13_03_2010, QUANTITY_1000) .and(addDaysToDate(dateDebut_13_03_2010, 1)
QUANTITY_3000) .build();
/** * 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; }}
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(); }}
@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);}
Tip4 (bis) : if/else fail()
if (sd.getTimeRef() == 0) {assertEquals(sd.getPrice(), "301");
} else {fail("pas normal");
}
assertThat(sd.getTimeRef()).isEqualTo(0);
assertEquals(sd.getPrice(), "301");
Guard Assert
Tip5 : Simili de toString() dans les assert
assertEquals("Compagnie differente : "+result.getId()+" / "+ result.getName() +" / "+ result.getLocation()
, result, expectedCompany);
assertThat(result).isEqualTo(expectedCompany);
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);
//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);
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);
}
@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");
}
Tip8 : Faire de belles assertions
• Ne surtout pas faire : – assertFalse(toto == null);– assertTrue(list.size() == 0);– assertEquals(result, null);
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
for (Company cie : companies) {Assert.assertFalse(cie.getStatus()
.equalsIgnoreCase(ConstantsUtils.SIMPLE_STATUS_ANNULE), "Cie " + cie.getId());
}
assertThat(companies).onProperty("status").containsOnly(SIMPLE_STATUS_VALIDE);
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/
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
FAIRE DES TESTS PLUS ROBUSTES
Tip1 : Pas de duplication
• Cf. Tip 3 : Masquer tout ce qui est inutile– Creation fixture– Creation builder
• Test Helper• Custom assertions
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);
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();}
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());}
@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());}
Tip4 : Quoi tester?
“Bas niveau” : état
private static String formatValue(Object removeNull) { if (removeNull == null) { return ""; } else { return removeNull.toString(); }}
“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 ;}
Bilan
• Aimez vos tests et ils vous le rendront
• Les principes “Clean code” s’appliquent également au code de test!
Ressources
• http://www.wakaleo.com/blog• http://misko.hevery.com/
MERCI
[email protected]://blog.xebia.fr