• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
2011 nri-pratiques tests-avancees
 

2011 nri-pratiques tests-avancees

on

  • 1,950 views

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

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

Statistics

Views

Total Views
1,950
Views on SlideShare
948
Embed Views
1,002

Actions

Likes
1
Downloads
17
Comments
0

7 Embeds 1,002

http://www.frenchsug.org 863
http://xnopre.blogspot.com 91
http://xnopre.blogspot.fr 39
url_unknown 4
http://xnopre.blogspot.be 3
http://translate.googleusercontent.com 1
http://xnopre.blogspot.ch 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • 3 symptomes :Plus d’assert@Test en commentaireCode commenté
  • MarketDataControllerBOTest
  • Chaque test porte une intention, un butOn ne teste pas une classe, mais plutôt un ensemble de comportement
  • Creation fixture (+varargs)Creation builder
  • Sortir les magic en constantes de classes
  • Plus facile pour détecter la méthodetestéeIncite à faire uneméthode de test = un testIncite à faire de petit tests
  • Fest
  • Fest
  • Fest
  • http://meetspock.appspot.com/Montrer:Nom de méthode en defGiven/When/Then : plus d’assertData Driven
  • http://meetspock.appspot.com/Montrer:Nom de méthode en defGiven/When/ThenData Driven
  • Inclus : Pas d’assertsur les init
  • Package private
  • Parler de dp4J : https://sites.google.com/a/mysimpatico.com/home//dp4j

2011 nri-pratiques tests-avancees 2011 nri-pratiques tests-avancees Presentation Transcript

  • Pratiques avancées de testsNathaniel Richand
    Scrumday France 2011
  • Merci aux sponsors du Scrumday !
    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 illisibleset fragiles
    Exemple
  • Constat :
    TDD peut :
    devenir un frein, diminuer le rythme
    Augmenter la rigidité du code
  • Améliorer la lisibilité
  • Tip1 : le nom donnel’intention
    testChoose1()
    testChoose2()
    whenSelectNullIItem_ShouldThrowAnException()
    whenSelectTwoItems_ShouldReturnTheSum()
  • Tip2 : Ne pas masquer les informationsutiles
    @DataSet
    publicclassBrokerDAOTestextendsUnitilsTestNG {
    @Test
    publicvoidtestGetNameByClauseInId() {
    BrokerDASbdao = newBrokerDAO();
    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
  • @Test
    publicvoidgenerateNomDeFichierNacXMLTest(){
    //Given
    NacCreatorBOnacCreator = newNacCreatorBO();
    //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");
    }
  • NacCreatorBOnacCreator;
    @Before
    publicvoidinit(){
    nacCreator= newNacCreatorBO();
    }
    @Test
    publicvoidgenerateNomDeFichierNacXMLTest(){
    //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");
    }
  • @Test
    publicvoidtestParserIntraday(){
    File file = new File("src/test/resources/fr/haramis/service/commons/util/Planning_Options.xls");
    List<IntradaySchedule> listIntradays = null;
    InputStreamstream = null;
    try{
    stream= newFileInputStream(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(IntradayScheduleintradaySchedule : listIntradays) {
    Assert.assertEquals(24, intradaySchedule.getIntraday().getIntradaySchedules().size());
    }
    }
    }
  • @Test
    publicvoidtestParserIntraday_OK() throws Exception{
    //Given
    InputStreamstream = getStreamFromFile("Planning_Options.xls");
    //When
    List<IntradaySchedule> listIntradays = IntradayParser.parseExcelIntraday(stream, "DIRECT-T01");
    //Then
    assertEquals(8400, listIntradays.size());
    for(IntradayScheduleintradaySchedule : listIntradays) {
    assertEquals(24, intradaySchedule.getIntraday()
    .getIntradaySchedules().size());
    }
    }
  • //Given
    Map<Date, BigDecimal> charges = newHashMap<Date, BigDecimal>();
    charges.put(dateDebut_13_03_2010,
    newBigDecimal(QUANTITY_1000));
    charges.put(addDaysToDate(dateDebut_13_03_2010, 1),
    newBigDecimal(QUANTITY_3000));
  • //Given
    Map<Date, BigDecimal> charges = newMapCharges<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>
    */
    privateclassMapCharges<T> {
    privateMap<T, BigDecimal> cdcMap = newHashMap<T, BigDecimal>();
    publicMapCharges<T> with(T dateDebut, intquantity){
    cdcMap.put(dateDebut, newBigDecimal(quantity));
    returnthis;
    }
    publicMapCharges<T> and(T dateDebut, intquantity){
    returnwith(dateDebut, quantity);
    }
    publicMap<T, BigDecimal> build(){
    returncdcMap;
    }
    }
  • Tip4 : try/catch fail()
    @Test
    publicvoidtestFindByStatutAndDate() {
    OrdreSpotDASdao = newOrdreSpotDAO();
    try{
    assertEquals(dao.findByDate("01/07/2008", "OK").size(), 2);
    assertEquals(dao.findByDate("01/07/2008", "KO").size(), 1);
    } catch (HaramisExceptione) {
    e.printStackTrace();
    Assert.fail();
    }
    }
  • @Test
    publicvoidtestFindByStatutAndDate() throwsHaramisException{
    OrdreSpotDASdao = newOrdreSpotDAO();
    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");
    GuardAssert
  • Tip5 : Simili de toString() dans les assert
    assertEquals("Compagniedifferente : "+result.getId()+" / "+ result.getName() +" / "+ result.getLocation()
    , result, expectedCompany);
    assertThat(result).isEqualTo(expectedCompany);
  • Tip6 : Magic number, magic null
    //Given
    Site siteNord = createSite(NORD, 10);
    Site siteSud = createSite(SUD, 12);
    //When
    intaffectations = dao.selectAffectationsNord(siteNord, siteSud, null);
    //Then
    assertThat(affectations).isEqualTo(10);
  • //Given
    Site siteNord = createSite(NORD, AFFECTATION_NORD);
    Site siteSud = createSite(SUD, AFFECTATION_SUD);
    //When
    intaffectations = dao.selectAffectationsNord(siteNord, siteSud, SITE_NULL);
    //Then
    assertThat(affectations).isEqualTo(AFFECTATION_NORD);
  • Tip7 : Garder la même structure
    @Test
    publicvoidcalculTotalTest(){
    //Given
    double[] volumes = {10.24556, 21, 43};
    //When
    double total = PositionUtils.calculTotal(UNITE_TEMPS_HORAIRE, volumes);
    //Then
    assertThat(total).isEqualTo(74.24556);
    }
  • @Test
    publicvoidcalculerDateTest(){
    //Given
    Date date = HaramisDateUtils.creerDateBlanchie(2010, 5, 19);
    //When
    String[] datesFormatees = PositionUtils.calculerDates(date, 1, UNITE_TEMPS_HORAIRE, ELECTRICTY);
    //Then
    assertThat(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 (Companycie : 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 = newRomanCalculator()when:    def result = calculator.add("I", "I")           then:    result == "II"
    }
    http://code.google.com/p/spock/
  • def"The lowestnumbershould go at the end"() {
    setup:
    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"  
    }
    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 seulendroit
    publicString formatResultToCSV(List<Object[]> positionsResultats) throwsParseException;
    privatestatic String[] calculerDeuxDates(Object[] ligne)
    throwsParseException;
    publicstatic String[] obtenirVolumes(Object[] ligne);
  • PublicString formatResultToCSV(List<Object[]> positionsResultats) throwsParseException {
    StringBuildersb = newStringBuilder();
    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+"|");
    }
    }
    returnsb.toString();
    }
  • Tip3 : Eviter la réflexion
    @Test
    publicvoid testReglesValidationHRM_118_KO() throws Exception {
    PortfolioManagerBOportfolioManagerBO = newPortfolioManagerBO();
    Method reglesValidationHRM118 = null;
    PortfolioFormportfolioForm = newPortfolioForm();
    portfolioManagerBO.setPortfolioForm(portfolioForm);
    reglesValidationHRM118 = ReflectHelper.getPrivateMethod(portfolioManagerBO, "reglesValidationHRM118");
    reglesValidationHRM118.setAccessible(true);
    reglesValidationHRM118.invoke(portfolioManagerBO);
    assertFalse(portfolioForm.isMessageAVisible());
    assertFalse(portfolioForm.isPopupVisible());
    }
  • @Test
    publicvoid testReglesValidationHRM_118_OK() throws Exception {
    //Given
    PortfolioManagerBOportfolioManagerBO = newPortfolioManagerBO();
    PortfolioFormportfolioForm = newPortfolioForm();
    portfolioManagerBO.setPortfolioForm(portfolioForm);
    //When
    portfolioManagerBO.reglesValidationHRM118();
    //Then
    assertFalse(portfolioForm.isMessageAVisible());
    assertFalse(portfolioForm.isPopupVisible());
    }
  • Tip4 : Quoi tester?
    “Bas niveau” : état
    privatestaticString formatValue(Object removeNull) {
    if(removeNull == null) {
    return"";
    } else {
    returnremoveNull.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);
    returnpointsCSV;
    }
  • 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
    nrichand@xebia.fr
    http://blog.xebia.fr