SlideShare une entreprise Scribd logo
1  sur  25
Tester unitairement
une application Java
11 février 2016
Objectifs
 Positionnement des TU par rapport aux autres catégories de tests
 Tour d’horizon des outils facilitant l’écriture de tests
 Zoom sur Mockito
 Exemples concrets
Sommaire
 Les différents types de tests automatisés
 Objectifs des tests unitaires
 Stratégies de mise en œuvre des tests unitaires
 Bonnes pratiques & Difficultés
 Décomposition d’un test
 L’intérêt des mocks
 Boîte à outils : Unitils, Mockito, DbUnit et Spring Test
 Exemples de tests de DAO et de contrôleurs Spring MVC
 Tester du code legacy
 Tests unitaires
 Teste une méthode d’une classe en isolation du reste de l’application
 Les tests exécutés lors d’un mvn test
 Doivent fonctionner sur un poste de dév déconnecté du réseau
 Outils : JUnit, Mockito
 Tests d’intégration
 Teste un ensemble de composants
 Exemples :
 Web Service SOAP ou REST
 Service métier s’appuyant sur un DAO Hibernate interrogeant une base Oracle
 Outils : JUnit, SoapUI
Les différents types de tests automatisés (1/2)
 Tests fonctionnels
 Exécute des scénarios fonctionnels en simulant des interactions utilisateurs
 Outils : Selenium, HP UFT, CasperJS, Cucumber
 Tests de performance
 Simule la charge utilisateur sur un environnement iso-prod
 Outils : JMeter, Gatling, Dynatrace
 Tests de vulnérabilité, de robustesse aux pannes, d’installation, de
déploiement …
Les différents types de tests automatisés (2/2)
 Vérifier le comportement d’une fonctionnalité au
regard des exigences
 Tester ses développements
 Fait partie du job d’un développeur
 Sérénité vis-à-vis des tests d’intégration
 Se prémunir de régression lors de :
 Correction d’anomalies
 Evolutions fonctionnelles
 Montée de socle technique
 Refactoring
Objectifs des tests unitaires (1/2)
 Documenter le code
 Contribuent
 au design logiciel
 à la qualité générale de l’application
Objectifs des tests unitaires (2/2)
 Tester en priorité :
 le code complexe
 les corrections de bugs
 le code sensible (souvent amené à changer)
 Tester les cas limites
 Tests en boîte noire / boîte blanche
Stratégies de mise en œuvre des tests unitaires
 Valider le fonctionnement par des assertions
 Automatiser l’exécution des TU
 Un TU doit être rapide à exécuter
 Essayer d’avoir une méthode de test par scénario de test
 L’échec d’un test unitaire doit être compréhensible
 Importance du nom de la méthode de test unitaire
Bonnes pratiques
 Jeux de données
 Demande une connaissance fonctionnelle
 Peut-être complexe et fastidieux à initier
 Tester la couche d’accès aux données
 Code existant éloigné des principes inspirés de Clean Code
Difficultés
 Un test se décompose généralement en 3 étapes
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class CalculatorTest {
@Test
public void evaluateAdditionExpression() {
Calculator calculator = new Calculator();
Expression exp = new ArithmeticExpression("1+2+3");
int sum = calculator.evaluate(exp);
assertEquals(6, sum);
}
}
Décomposition d’un test
3. Then : vérifications du résultat
2. When : appel de la méthode testée
1. Given : initialise l’état du système
 Besoin : tester individuellement un service métier,
c’est à dire sans ses adhérences
L’intérêt des mocks
Service
Dao
Service
Dao
Mock
Code de production Configuration de test
à programmer
 ReflectionAssert.assertReflectionEquals de unitils-core
Boîte à outils : assertReflectionEquals de Unitils
User user1 = new User(1, "John", "Doe");
User user2 = new User(1, "John", "Connor");
assertReflectionEquals(user1, user2);
junit.framework.AssertionFailedError:
Expected: User<id=1, firstname="John", lastname="Doe">
Actual: User<id=1, firstname="John", lastname="Connor">
--- Found following differences ---
lastname: expected: "Doe", actual: "Connor"
Boîte à outils : Spring Test
 Conteneur léger accessible aux tests unitaires et d’intégration
 Support de JUnit 4 et TestNG
 Chargement du contexte Spring
 Injection de dépendances
 Mise en cache du contexte Spring
 Extensions de JUnit par
 Runner : SpringJUnit4ClassRunner
 Annotations : @ContextConfiguration, @Rollback, @Sql, @Repeat, @ActiveProfiles …
 Listeners : DependencyInjectionTestExecutionListener
 Bouchons prêts à l’emploi : MockHttpSession, MockHttpServletRequest …
 Classes utilitaires : JdbcTestUtils, AopTestUtils, ReflectionTestUtils,
TestTransaction …
 Spring MVC Test Framework
 Permet de charger en base des jeux de données
 A partir de fichier XML
 Favoriser des dataset les plus petits possibles
 Suite à un test, permet de vérifier l’état de la base
 Comparaison de l’état de la base avec un fichier XML
 Ce que DbUnit ne fait pas :
 Création de la base et du schéma
 Gestion des connexions et des transactions
 L’élaboration de jeux de données
Boîte à outils : DbUnit
 Créer un mock
Boîte à outils : Mockito (1/4)
import static org.mockito.Mockito.*;
List mockedList = mock(List.class);
assertNull(mockedList.get(0)); Les méthodes d’un mock non programmé
ne font rien. Elles retournent null ou false .
 Programmer un mock
LinkedList mockedList = mock(LinkedList.class);
when(mockedList.get(0)).thenReturn("first");
assertEquals("first", mockedList.get(0));
assertNull(mockedList.get(1));
Mockito permet de mocker aussi bien
des interfaces que des classes.
Simule un comportement
 Vérifier les interactions avec le mock
Boîte à outils : Mockito (2/4)
@Test
public void testAdminAuthentication() {
UserDao userDao = mock(UserDao.class);
UserService userService = new UserService(userDao);
User admin = new User("admin");
when(userDao.findOne("admin")).thenReturn(admin);
User loadedUser = userService.loadUserByUsername("admin");
verify(userDao).findOne("admin");
}
Mock le DAO
Programme le DAO
Vérifie l’interaction
 A utiliser judicieusement
 Lorsque la méthode testée ne renvoie pas de résultat
 Pour des problématiques de performance
 Partial mocking avec spy
 Enregistre les interactions
 Simule le comportement de méthodes choisies
Boîte à outils : Mockito (3/4)
List<String> list = new ArrayList<String>();
List<String> spyList = Mockito.spy(list);
spyList.add("one");
assertEquals(1, spyList.size());
Mockito.verify(spyList).add("one");
when(spyList.size()).doReturn(100);
assertEquals(100, spyList.size());
 ArgumentCaptor
Permet de récupérer la valeur des
paramètres d’appel d’un mock
Boîte à outils : Mockito (4/4)
public class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void inviteToParty(Person friend,
Party party) {
party.addGuest(friend);
}
}
ArgumentCaptor<Person> argument =
ArgumentCaptor.forClass(Person.class);
Party party = mock(Party.class);
Person john = new Person("John");
Person peter = new Person("Peter");
// Peter invites John to the party
peter.inviteToParty(john, party);
verify(party).addGuest(argument.capture());
// verify John was invited
assertEquals("John", argument.getValue().getName());
 Tester unitairement des DAO nécessite une base de données embarquée
 Les puristes les considèrent comme des tests d’intégration
 Spring Test
 Facilite le chargement de la configuration Spring liée à l’infrastructure
 Prend en charge la création du schéma
 Support des transactions
 Laisse la base inchangée après l’exécution du test (débrayable)
 Gestion manuelle des transactions
 Possibilité d’exécuter du code en dehors d’une transaction
Tester des DAO (1/3)
Tester des DAO (2/3)
 Avec DbUnit
accounts-dataset.xml
<?xml version='1.0' encoding='UTF-8'?>
<dataset>
<ACCOUNT ID="1" BIC="FR7030002005500000157845Z02" LABEL="Account 1"/>
<ACCOUNT ID="2" BIC="FR70300023455000021Z4234Y45" LABEL="Account 2"/>
</dataset>
public class TestHibernateAccountDao extend AbstractDaoTest<HibernateAccountDao> {
@Test
public void findAccountByIBan() {
DbUnitLoader.loadDataset("accounts-dataset.xml");
String iban = "FR70 3000 2005 5000 0015 7845 Z02";
Account account = dao.findAccountByIBan(iban);
assertNotNull(account);
assertEquals("Account 1", account.getDescription());
}
}
 Avec Spring Test
Tester des DAO (3/3)
Extrait du fichier spring/dao-config.xml
<beans profile="test">
<jdbc:embedded-database id="dataSource" type="HSQL">
<jdbc:script location="classpath:create-schema.sql"/>
</jdbc:embedded-database>
</beans>
<beans profile="production">
<jee:jndi-lookup id="dataSource"
jndi-name="jdbc/MyDataSource"/>
</beans>
<bean id="sessionFactory"
class="o.s.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref=" dataSource " />
…
</bean>
<bean id="transactionManager"
class="o.s.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<context:component-scan base-package="com.myapp.dao"/>
@ContextConfiguration(locations = {"classpath:spring/dao-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("test")
public class ClinicDaoTests {
@Autowired ClinicDao clinicDao;
}
@Test @Transactional
public void shouldInsertOwner() {
Collection<Owner> owners = clinicDao.findOwnerByLastName("Schultz");
int found = owners.size();
Owner owner = new Owner();
owner.setFirstName("Sam");
owner.setLastName("Schultz");
owner.setAddress("4, Evans Street");
owner.setCity("Wollongong");
clinicDao.saveOwner(owner);
assertThat(owner.getId().longValue()).isNotEqualTo(0);
owners = clinicDao.findOwnerByLastName("Schultz");
assertThat(owners.size()).isEqualTo(found + 1);
}
 Avec Spring Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring/mvc-core-config.xml"})
@WebAppConfiguration
public class PetControllerTests {
@Autowired PetController petController;
MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(petController) .build();
}
@Test
public void testProcessUpdateFormSuccess() throws Exception {
mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", 1,1)
.param("name", "Betty")
.param("type", "hamster")
.param("birthDate", "2015/02/12")
)
.andExpect(status().is3xxRedirection())
.andExpect(view().name("redirect:/owners/{ownerId}"));
} }
Tester un contrôleur Spring MVC
Tester du code legacy
 Code faisant appel à un Singleton avec getIntance()
 Création d’un setter de visibilité package permettant de passer un
mock
 Méthode phagocyte
 Refactoring en sous méthodes qui seront testées individuellement
 Méthode private
 Changement de la visibilité en portée package
Conclusion
 Ecrire des tests, cela s’apprend
 Tester unitairement, c’est coder
 A chaque couche / techno, sa typologie de test

Contenu connexe

Tendances

Formation Spring Avancé gratuite par Ippon 2014
Formation Spring Avancé gratuite par Ippon 2014Formation Spring Avancé gratuite par Ippon 2014
Formation Spring Avancé gratuite par Ippon 2014Ippon
 
Architecture jee principe de inversion de controle et injection des dependances
Architecture jee principe de inversion de controle et injection des dependancesArchitecture jee principe de inversion de controle et injection des dependances
Architecture jee principe de inversion de controle et injection des dependancesENSET, Université Hassan II Casablanca
 
Workshop spring session 2 - La persistance au sein des applications Java
Workshop spring   session 2 - La persistance au sein des applications JavaWorkshop spring   session 2 - La persistance au sein des applications Java
Workshop spring session 2 - La persistance au sein des applications JavaAntoine Rey
 
Mohamed youssfi support architectures logicielles distribuées basées sue les ...
Mohamed youssfi support architectures logicielles distribuées basées sue les ...Mohamed youssfi support architectures logicielles distribuées basées sue les ...
Mohamed youssfi support architectures logicielles distribuées basées sue les ...ENSET, Université Hassan II Casablanca
 
Fondamentaux java
Fondamentaux javaFondamentaux java
Fondamentaux javaInes Ouaz
 
La gestion des exceptions avec Java
La gestion des exceptions avec JavaLa gestion des exceptions avec Java
La gestion des exceptions avec JavaPapa Cheikh Cisse
 
Développement d'un site web jee de e commerce basé sur spring (m.youssfi)
Développement d'un site web jee de e commerce basé sur spring (m.youssfi)Développement d'un site web jee de e commerce basé sur spring (m.youssfi)
Développement d'un site web jee de e commerce basé sur spring (m.youssfi)ENSET, Université Hassan II Casablanca
 
Java 8 - collections et stream
Java 8 - collections et streamJava 8 - collections et stream
Java 8 - collections et streamFranck SIMON
 

Tendances (20)

Formation Spring Avancé gratuite par Ippon 2014
Formation Spring Avancé gratuite par Ippon 2014Formation Spring Avancé gratuite par Ippon 2014
Formation Spring Avancé gratuite par Ippon 2014
 
Architecture jee principe de inversion de controle et injection des dependances
Architecture jee principe de inversion de controle et injection des dependancesArchitecture jee principe de inversion de controle et injection des dependances
Architecture jee principe de inversion de controle et injection des dependances
 
Workshop spring session 2 - La persistance au sein des applications Java
Workshop spring   session 2 - La persistance au sein des applications JavaWorkshop spring   session 2 - La persistance au sein des applications Java
Workshop spring session 2 - La persistance au sein des applications Java
 
Spring Core
Spring CoreSpring Core
Spring Core
 
Mohamed youssfi support architectures logicielles distribuées basées sue les ...
Mohamed youssfi support architectures logicielles distribuées basées sue les ...Mohamed youssfi support architectures logicielles distribuées basées sue les ...
Mohamed youssfi support architectures logicielles distribuées basées sue les ...
 
spring-api-rest.pdf
spring-api-rest.pdfspring-api-rest.pdf
spring-api-rest.pdf
 
Fondamentaux java
Fondamentaux javaFondamentaux java
Fondamentaux java
 
Support de cours Spring M.youssfi
Support de cours Spring  M.youssfiSupport de cours Spring  M.youssfi
Support de cours Spring M.youssfi
 
Spring Security 5
Spring Security 5Spring Security 5
Spring Security 5
 
La gestion des exceptions avec Java
La gestion des exceptions avec JavaLa gestion des exceptions avec Java
La gestion des exceptions avec Java
 
Support de cours angular
Support de cours angularSupport de cours angular
Support de cours angular
 
Hibernate jpa
Hibernate jpaHibernate jpa
Hibernate jpa
 
Spring mvc
Spring mvcSpring mvc
Spring mvc
 
Support Java Avancé Troisième Partie
Support Java Avancé Troisième PartieSupport Java Avancé Troisième Partie
Support Java Avancé Troisième Partie
 
Hibernate
HibernateHibernate
Hibernate
 
Support de cours technologie et application m.youssfi
Support de cours technologie et application m.youssfiSupport de cours technologie et application m.youssfi
Support de cours technologie et application m.youssfi
 
Spring security
Spring securitySpring security
Spring security
 
Développement d'un site web jee de e commerce basé sur spring (m.youssfi)
Développement d'un site web jee de e commerce basé sur spring (m.youssfi)Développement d'un site web jee de e commerce basé sur spring (m.youssfi)
Développement d'un site web jee de e commerce basé sur spring (m.youssfi)
 
Java 8 - collections et stream
Java 8 - collections et streamJava 8 - collections et stream
Java 8 - collections et stream
 
Support POO Java première partie
Support POO Java première partieSupport POO Java première partie
Support POO Java première partie
 

En vedette

Les dessous du framework spring
Les dessous du framework springLes dessous du framework spring
Les dessous du framework springAntoine Rey
 
Microservices with .Net - NDC Sydney, 2016
Microservices with .Net - NDC Sydney, 2016Microservices with .Net - NDC Sydney, 2016
Microservices with .Net - NDC Sydney, 2016Richard Banks
 
Learned optimism
Learned optimismLearned optimism
Learned optimismAndrew Chaa
 
Introduction à Angular JS
Introduction à Angular JSIntroduction à Angular JS
Introduction à Angular JSAntoine Rey
 
Workshop Spring - Session 5 - Spring Integration
Workshop Spring - Session 5 - Spring IntegrationWorkshop Spring - Session 5 - Spring Integration
Workshop Spring - Session 5 - Spring IntegrationAntoine Rey
 
Retours Devoxx France 2016
Retours Devoxx France 2016Retours Devoxx France 2016
Retours Devoxx France 2016Antoine Rey
 
Workshop Spring - Session 1 - L'offre Spring et les bases
Workshop Spring  - Session 1 - L'offre Spring et les basesWorkshop Spring  - Session 1 - L'offre Spring et les bases
Workshop Spring - Session 1 - L'offre Spring et les basesAntoine Rey
 
Les Streams de Java 8
Les Streams de Java 8Les Streams de Java 8
Les Streams de Java 8Antoine Rey
 
pessimistic-development-presentation
pessimistic-development-presentationpessimistic-development-presentation
pessimistic-development-presentationJonathan Marbutt
 
Ces outils qui vous font gagner du temps
Ces outils qui vous font gagner du tempsCes outils qui vous font gagner du temps
Ces outils qui vous font gagner du tempsAntoine Rey
 
Workshop Spring 3 - Tests et techniques avancées du conteneur Spring
Workshop Spring  3 - Tests et techniques avancées du conteneur SpringWorkshop Spring  3 - Tests et techniques avancées du conteneur Spring
Workshop Spring 3 - Tests et techniques avancées du conteneur SpringAntoine Rey
 
Spring Framework Petclinic sample application
Spring Framework Petclinic sample applicationSpring Framework Petclinic sample application
Spring Framework Petclinic sample applicationAntoine Rey
 
Quoi de neuf à Devoxx France 2017 ?
Quoi de neuf à Devoxx France 2017 ?Quoi de neuf à Devoxx France 2017 ?
Quoi de neuf à Devoxx France 2017 ?Antoine Rey
 

En vedette (13)

Les dessous du framework spring
Les dessous du framework springLes dessous du framework spring
Les dessous du framework spring
 
Microservices with .Net - NDC Sydney, 2016
Microservices with .Net - NDC Sydney, 2016Microservices with .Net - NDC Sydney, 2016
Microservices with .Net - NDC Sydney, 2016
 
Learned optimism
Learned optimismLearned optimism
Learned optimism
 
Introduction à Angular JS
Introduction à Angular JSIntroduction à Angular JS
Introduction à Angular JS
 
Workshop Spring - Session 5 - Spring Integration
Workshop Spring - Session 5 - Spring IntegrationWorkshop Spring - Session 5 - Spring Integration
Workshop Spring - Session 5 - Spring Integration
 
Retours Devoxx France 2016
Retours Devoxx France 2016Retours Devoxx France 2016
Retours Devoxx France 2016
 
Workshop Spring - Session 1 - L'offre Spring et les bases
Workshop Spring  - Session 1 - L'offre Spring et les basesWorkshop Spring  - Session 1 - L'offre Spring et les bases
Workshop Spring - Session 1 - L'offre Spring et les bases
 
Les Streams de Java 8
Les Streams de Java 8Les Streams de Java 8
Les Streams de Java 8
 
pessimistic-development-presentation
pessimistic-development-presentationpessimistic-development-presentation
pessimistic-development-presentation
 
Ces outils qui vous font gagner du temps
Ces outils qui vous font gagner du tempsCes outils qui vous font gagner du temps
Ces outils qui vous font gagner du temps
 
Workshop Spring 3 - Tests et techniques avancées du conteneur Spring
Workshop Spring  3 - Tests et techniques avancées du conteneur SpringWorkshop Spring  3 - Tests et techniques avancées du conteneur Spring
Workshop Spring 3 - Tests et techniques avancées du conteneur Spring
 
Spring Framework Petclinic sample application
Spring Framework Petclinic sample applicationSpring Framework Petclinic sample application
Spring Framework Petclinic sample application
 
Quoi de neuf à Devoxx France 2017 ?
Quoi de neuf à Devoxx France 2017 ?Quoi de neuf à Devoxx France 2017 ?
Quoi de neuf à Devoxx France 2017 ?
 

Similaire à Tester unitairement une application java

Comment écrire du code testable ?
Comment écrire du code testable ?Comment écrire du code testable ?
Comment écrire du code testable ?Fou Cha
 
testUnitaire (1).pptx
testUnitaire (1).pptxtestUnitaire (1).pptx
testUnitaire (1).pptxManalAg
 
Automatisation des tests - objectifs et concepts - partie 2
Automatisation des tests  - objectifs et concepts - partie 2Automatisation des tests  - objectifs et concepts - partie 2
Automatisation des tests - objectifs et concepts - partie 2Christophe Rochefolle
 
Java 9 modulo les modules devoxx fr 2017
Java 9 modulo les modules devoxx fr 2017Java 9 modulo les modules devoxx fr 2017
Java 9 modulo les modules devoxx fr 2017Jean-Michel Doudoux
 
Qualité logicielle
Qualité logicielleQualité logicielle
Qualité logiciellecyrilgandon
 
Xdt Tests Driven Architecture Process V1.0
Xdt Tests Driven Architecture Process V1.0Xdt Tests Driven Architecture Process V1.0
Xdt Tests Driven Architecture Process V1.0guestee837a
 
La Tooling API, est-ce pour moi ? Bien sûr, viens voir pourquoi !
La Tooling API, est-ce pour moi ? Bien sûr, viens voir pourquoi !La Tooling API, est-ce pour moi ? Bien sûr, viens voir pourquoi !
La Tooling API, est-ce pour moi ? Bien sûr, viens voir pourquoi !Paris Salesforce Developer Group
 
201303 - Java8
201303 - Java8201303 - Java8
201303 - Java8lyonjug
 
RefCard Tests sur tous les fronts
RefCard Tests sur tous les frontsRefCard Tests sur tous les fronts
RefCard Tests sur tous les frontsOCTO Technology
 
Tester avant de déployer ; comment tester ses déploiements ARM.
Tester avant de déployer ; comment tester ses déploiements ARM.Tester avant de déployer ; comment tester ses déploiements ARM.
Tester avant de déployer ; comment tester ses déploiements ARM.AZUG FR
 
05 visual basic .net - variables, procedures, arguments et structures de cont...
05 visual basic .net - variables, procedures, arguments et structures de cont...05 visual basic .net - variables, procedures, arguments et structures de cont...
05 visual basic .net - variables, procedures, arguments et structures de cont...Hamza SAID
 
PréSentation Qualoo Le Generateur De Code Java J2 Ee
PréSentation Qualoo   Le Generateur De Code Java J2 EePréSentation Qualoo   Le Generateur De Code Java J2 Ee
PréSentation Qualoo Le Generateur De Code Java J2 EeST informatique services
 
Intro sur les tests unitaires
Intro sur les tests unitairesIntro sur les tests unitaires
Intro sur les tests unitairesPHPPRO
 
Atoum, le framework de tests unitaires pour PHP 5.3 simple, moderne et intuit...
Atoum, le framework de tests unitaires pour PHP 5.3 simple, moderne et intuit...Atoum, le framework de tests unitaires pour PHP 5.3 simple, moderne et intuit...
Atoum, le framework de tests unitaires pour PHP 5.3 simple, moderne et intuit...fdussert
 
[PFE] Master en ingénierie du logiciel
[PFE] Master en ingénierie du logiciel[PFE] Master en ingénierie du logiciel
[PFE] Master en ingénierie du logicielUSTHB & DELTALOG
 

Similaire à Tester unitairement une application java (20)

Bbl sur les tests
Bbl sur les testsBbl sur les tests
Bbl sur les tests
 
J Unit
J UnitJ Unit
J Unit
 
Comment écrire du code testable ?
Comment écrire du code testable ?Comment écrire du code testable ?
Comment écrire du code testable ?
 
testUnitaire (1).pptx
testUnitaire (1).pptxtestUnitaire (1).pptx
testUnitaire (1).pptx
 
Automatisation des tests - objectifs et concepts - partie 2
Automatisation des tests  - objectifs et concepts - partie 2Automatisation des tests  - objectifs et concepts - partie 2
Automatisation des tests - objectifs et concepts - partie 2
 
Les tests en PHP
Les tests en PHPLes tests en PHP
Les tests en PHP
 
Java 9 modulo les modules devoxx fr 2017
Java 9 modulo les modules devoxx fr 2017Java 9 modulo les modules devoxx fr 2017
Java 9 modulo les modules devoxx fr 2017
 
Présentation nouveauté java7
Présentation nouveauté java7Présentation nouveauté java7
Présentation nouveauté java7
 
Qualité logicielle
Qualité logicielleQualité logicielle
Qualité logicielle
 
Qualité de code et bonnes pratiques
Qualité de code et bonnes pratiquesQualité de code et bonnes pratiques
Qualité de code et bonnes pratiques
 
Xdt Tests Driven Architecture Process V1.0
Xdt Tests Driven Architecture Process V1.0Xdt Tests Driven Architecture Process V1.0
Xdt Tests Driven Architecture Process V1.0
 
La Tooling API, est-ce pour moi ? Bien sûr, viens voir pourquoi !
La Tooling API, est-ce pour moi ? Bien sûr, viens voir pourquoi !La Tooling API, est-ce pour moi ? Bien sûr, viens voir pourquoi !
La Tooling API, est-ce pour moi ? Bien sûr, viens voir pourquoi !
 
201303 - Java8
201303 - Java8201303 - Java8
201303 - Java8
 
RefCard Tests sur tous les fronts
RefCard Tests sur tous les frontsRefCard Tests sur tous les fronts
RefCard Tests sur tous les fronts
 
Tester avant de déployer ; comment tester ses déploiements ARM.
Tester avant de déployer ; comment tester ses déploiements ARM.Tester avant de déployer ; comment tester ses déploiements ARM.
Tester avant de déployer ; comment tester ses déploiements ARM.
 
05 visual basic .net - variables, procedures, arguments et structures de cont...
05 visual basic .net - variables, procedures, arguments et structures de cont...05 visual basic .net - variables, procedures, arguments et structures de cont...
05 visual basic .net - variables, procedures, arguments et structures de cont...
 
PréSentation Qualoo Le Generateur De Code Java J2 Ee
PréSentation Qualoo   Le Generateur De Code Java J2 EePréSentation Qualoo   Le Generateur De Code Java J2 Ee
PréSentation Qualoo Le Generateur De Code Java J2 Ee
 
Intro sur les tests unitaires
Intro sur les tests unitairesIntro sur les tests unitaires
Intro sur les tests unitaires
 
Atoum, le framework de tests unitaires pour PHP 5.3 simple, moderne et intuit...
Atoum, le framework de tests unitaires pour PHP 5.3 simple, moderne et intuit...Atoum, le framework de tests unitaires pour PHP 5.3 simple, moderne et intuit...
Atoum, le framework de tests unitaires pour PHP 5.3 simple, moderne et intuit...
 
[PFE] Master en ingénierie du logiciel
[PFE] Master en ingénierie du logiciel[PFE] Master en ingénierie du logiciel
[PFE] Master en ingénierie du logiciel
 

Tester unitairement une application java

  • 1. Tester unitairement une application Java 11 février 2016
  • 2. Objectifs  Positionnement des TU par rapport aux autres catégories de tests  Tour d’horizon des outils facilitant l’écriture de tests  Zoom sur Mockito  Exemples concrets
  • 3. Sommaire  Les différents types de tests automatisés  Objectifs des tests unitaires  Stratégies de mise en œuvre des tests unitaires  Bonnes pratiques & Difficultés  Décomposition d’un test  L’intérêt des mocks  Boîte à outils : Unitils, Mockito, DbUnit et Spring Test  Exemples de tests de DAO et de contrôleurs Spring MVC  Tester du code legacy
  • 4.  Tests unitaires  Teste une méthode d’une classe en isolation du reste de l’application  Les tests exécutés lors d’un mvn test  Doivent fonctionner sur un poste de dév déconnecté du réseau  Outils : JUnit, Mockito  Tests d’intégration  Teste un ensemble de composants  Exemples :  Web Service SOAP ou REST  Service métier s’appuyant sur un DAO Hibernate interrogeant une base Oracle  Outils : JUnit, SoapUI Les différents types de tests automatisés (1/2)
  • 5.  Tests fonctionnels  Exécute des scénarios fonctionnels en simulant des interactions utilisateurs  Outils : Selenium, HP UFT, CasperJS, Cucumber  Tests de performance  Simule la charge utilisateur sur un environnement iso-prod  Outils : JMeter, Gatling, Dynatrace  Tests de vulnérabilité, de robustesse aux pannes, d’installation, de déploiement … Les différents types de tests automatisés (2/2)
  • 6.  Vérifier le comportement d’une fonctionnalité au regard des exigences  Tester ses développements  Fait partie du job d’un développeur  Sérénité vis-à-vis des tests d’intégration  Se prémunir de régression lors de :  Correction d’anomalies  Evolutions fonctionnelles  Montée de socle technique  Refactoring Objectifs des tests unitaires (1/2)
  • 7.  Documenter le code  Contribuent  au design logiciel  à la qualité générale de l’application Objectifs des tests unitaires (2/2)
  • 8.  Tester en priorité :  le code complexe  les corrections de bugs  le code sensible (souvent amené à changer)  Tester les cas limites  Tests en boîte noire / boîte blanche Stratégies de mise en œuvre des tests unitaires
  • 9.  Valider le fonctionnement par des assertions  Automatiser l’exécution des TU  Un TU doit être rapide à exécuter  Essayer d’avoir une méthode de test par scénario de test  L’échec d’un test unitaire doit être compréhensible  Importance du nom de la méthode de test unitaire Bonnes pratiques
  • 10.  Jeux de données  Demande une connaissance fonctionnelle  Peut-être complexe et fastidieux à initier  Tester la couche d’accès aux données  Code existant éloigné des principes inspirés de Clean Code Difficultés
  • 11.  Un test se décompose généralement en 3 étapes import static org.junit.Assert.assertEquals; import org.junit.Test; public class CalculatorTest { @Test public void evaluateAdditionExpression() { Calculator calculator = new Calculator(); Expression exp = new ArithmeticExpression("1+2+3"); int sum = calculator.evaluate(exp); assertEquals(6, sum); } } Décomposition d’un test 3. Then : vérifications du résultat 2. When : appel de la méthode testée 1. Given : initialise l’état du système
  • 12.  Besoin : tester individuellement un service métier, c’est à dire sans ses adhérences L’intérêt des mocks Service Dao Service Dao Mock Code de production Configuration de test à programmer
  • 13.  ReflectionAssert.assertReflectionEquals de unitils-core Boîte à outils : assertReflectionEquals de Unitils User user1 = new User(1, "John", "Doe"); User user2 = new User(1, "John", "Connor"); assertReflectionEquals(user1, user2); junit.framework.AssertionFailedError: Expected: User<id=1, firstname="John", lastname="Doe"> Actual: User<id=1, firstname="John", lastname="Connor"> --- Found following differences --- lastname: expected: "Doe", actual: "Connor"
  • 14. Boîte à outils : Spring Test  Conteneur léger accessible aux tests unitaires et d’intégration  Support de JUnit 4 et TestNG  Chargement du contexte Spring  Injection de dépendances  Mise en cache du contexte Spring  Extensions de JUnit par  Runner : SpringJUnit4ClassRunner  Annotations : @ContextConfiguration, @Rollback, @Sql, @Repeat, @ActiveProfiles …  Listeners : DependencyInjectionTestExecutionListener  Bouchons prêts à l’emploi : MockHttpSession, MockHttpServletRequest …  Classes utilitaires : JdbcTestUtils, AopTestUtils, ReflectionTestUtils, TestTransaction …  Spring MVC Test Framework
  • 15.  Permet de charger en base des jeux de données  A partir de fichier XML  Favoriser des dataset les plus petits possibles  Suite à un test, permet de vérifier l’état de la base  Comparaison de l’état de la base avec un fichier XML  Ce que DbUnit ne fait pas :  Création de la base et du schéma  Gestion des connexions et des transactions  L’élaboration de jeux de données Boîte à outils : DbUnit
  • 16.  Créer un mock Boîte à outils : Mockito (1/4) import static org.mockito.Mockito.*; List mockedList = mock(List.class); assertNull(mockedList.get(0)); Les méthodes d’un mock non programmé ne font rien. Elles retournent null ou false .  Programmer un mock LinkedList mockedList = mock(LinkedList.class); when(mockedList.get(0)).thenReturn("first"); assertEquals("first", mockedList.get(0)); assertNull(mockedList.get(1)); Mockito permet de mocker aussi bien des interfaces que des classes. Simule un comportement
  • 17.  Vérifier les interactions avec le mock Boîte à outils : Mockito (2/4) @Test public void testAdminAuthentication() { UserDao userDao = mock(UserDao.class); UserService userService = new UserService(userDao); User admin = new User("admin"); when(userDao.findOne("admin")).thenReturn(admin); User loadedUser = userService.loadUserByUsername("admin"); verify(userDao).findOne("admin"); } Mock le DAO Programme le DAO Vérifie l’interaction  A utiliser judicieusement  Lorsque la méthode testée ne renvoie pas de résultat  Pour des problématiques de performance
  • 18.  Partial mocking avec spy  Enregistre les interactions  Simule le comportement de méthodes choisies Boîte à outils : Mockito (3/4) List<String> list = new ArrayList<String>(); List<String> spyList = Mockito.spy(list); spyList.add("one"); assertEquals(1, spyList.size()); Mockito.verify(spyList).add("one"); when(spyList.size()).doReturn(100); assertEquals(100, spyList.size());
  • 19.  ArgumentCaptor Permet de récupérer la valeur des paramètres d’appel d’un mock Boîte à outils : Mockito (4/4) public class Person { private final String name; public Person(String name) { this.name = name; } public String getName() { return name; } public void inviteToParty(Person friend, Party party) { party.addGuest(friend); } } ArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class); Party party = mock(Party.class); Person john = new Person("John"); Person peter = new Person("Peter"); // Peter invites John to the party peter.inviteToParty(john, party); verify(party).addGuest(argument.capture()); // verify John was invited assertEquals("John", argument.getValue().getName());
  • 20.  Tester unitairement des DAO nécessite une base de données embarquée  Les puristes les considèrent comme des tests d’intégration  Spring Test  Facilite le chargement de la configuration Spring liée à l’infrastructure  Prend en charge la création du schéma  Support des transactions  Laisse la base inchangée après l’exécution du test (débrayable)  Gestion manuelle des transactions  Possibilité d’exécuter du code en dehors d’une transaction Tester des DAO (1/3)
  • 21. Tester des DAO (2/3)  Avec DbUnit accounts-dataset.xml <?xml version='1.0' encoding='UTF-8'?> <dataset> <ACCOUNT ID="1" BIC="FR7030002005500000157845Z02" LABEL="Account 1"/> <ACCOUNT ID="2" BIC="FR70300023455000021Z4234Y45" LABEL="Account 2"/> </dataset> public class TestHibernateAccountDao extend AbstractDaoTest<HibernateAccountDao> { @Test public void findAccountByIBan() { DbUnitLoader.loadDataset("accounts-dataset.xml"); String iban = "FR70 3000 2005 5000 0015 7845 Z02"; Account account = dao.findAccountByIBan(iban); assertNotNull(account); assertEquals("Account 1", account.getDescription()); } }
  • 22.  Avec Spring Test Tester des DAO (3/3) Extrait du fichier spring/dao-config.xml <beans profile="test"> <jdbc:embedded-database id="dataSource" type="HSQL"> <jdbc:script location="classpath:create-schema.sql"/> </jdbc:embedded-database> </beans> <beans profile="production"> <jee:jndi-lookup id="dataSource" jndi-name="jdbc/MyDataSource"/> </beans> <bean id="sessionFactory" class="o.s.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref=" dataSource " /> … </bean> <bean id="transactionManager" class="o.s.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <context:component-scan base-package="com.myapp.dao"/> @ContextConfiguration(locations = {"classpath:spring/dao-config.xml"}) @RunWith(SpringJUnit4ClassRunner.class) @ActiveProfiles("test") public class ClinicDaoTests { @Autowired ClinicDao clinicDao; } @Test @Transactional public void shouldInsertOwner() { Collection<Owner> owners = clinicDao.findOwnerByLastName("Schultz"); int found = owners.size(); Owner owner = new Owner(); owner.setFirstName("Sam"); owner.setLastName("Schultz"); owner.setAddress("4, Evans Street"); owner.setCity("Wollongong"); clinicDao.saveOwner(owner); assertThat(owner.getId().longValue()).isNotEqualTo(0); owners = clinicDao.findOwnerByLastName("Schultz"); assertThat(owners.size()).isEqualTo(found + 1); }
  • 23.  Avec Spring Test @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:spring/mvc-core-config.xml"}) @WebAppConfiguration public class PetControllerTests { @Autowired PetController petController; MockMvc mockMvc; @Before public void setup() { mockMvc = MockMvcBuilders.standaloneSetup(petController) .build(); } @Test public void testProcessUpdateFormSuccess() throws Exception { mockMvc.perform(post("/owners/{ownerId}/pets/{petId}/edit", 1,1) .param("name", "Betty") .param("type", "hamster") .param("birthDate", "2015/02/12") ) .andExpect(status().is3xxRedirection()) .andExpect(view().name("redirect:/owners/{ownerId}")); } } Tester un contrôleur Spring MVC
  • 24. Tester du code legacy  Code faisant appel à un Singleton avec getIntance()  Création d’un setter de visibilité package permettant de passer un mock  Méthode phagocyte  Refactoring en sous méthodes qui seront testées individuellement  Méthode private  Changement de la visibilité en portée package
  • 25. Conclusion  Ecrire des tests, cela s’apprend  Tester unitairement, c’est coder  A chaque couche / techno, sa typologie de test

Notes de l'éditeur

  1. Classement personnel issu d’un certain pragmatisme Test de la configuration Spring s’apparente davantage un test d’intégration mais comme stable et relativement rapide => TU ? Utilisation d’une base de données en mémoire ?
  2. Tests fonctionnels  tests d’acceptance / tests d’IHM HP Fortify permet de tester la vulnérabilité du code à l’égard de failles de sécurité Ces 4 types de tests sont complémentaires. Un TU garantie que le contrat de la classe à tester est respectée mais ne garantie pas que l’application respecte les spécifications fonctionnelles. De part leur nature, les tests d’intégration et les tests fonctionnels sont moins stables : dépendances aux données, à la disponibilité des adhérences, à l’infra …
  3. Objectif premier lorsqu’on ne pratique pas le TDD : trouver des bugs Le TU fait partie du Done en agile Les TU permettent au CP de s’assurer à minima que le développeur à tester son code Se prémunir de régression : penser aux autres développeurs qui maintiendront l’application Un harnais de tests est toujours sécurisant
  4. Documenter le code : Spring REST Docs utilise les tests pour générer la doc de son API web. Contrairement à la JavaDoc, les TU sont toujours à jour. Contribue au design de l’application : un code testable est souvent plus lisible / maintenable (pas de singleton ou de méthodes phagocytes) Design logiciel : couplage faible (IoC), principe de substitution de Liskow (emploi correct de l’héritage), conception orientée service
  5. L’écriture de TU a un coût (souvent estimé à 20% de la charge de dévs) et sa maintenance en a également un, Eviter de tester du code legacy qui ne change jamais
  6. Des TU sans assertions ne servent à rien (mise à part vérifier qu’aucune exception n’est levée) Un TU non exécuté (@Ignore ou EclipseTestXXX) n’est pas maintenu Nom des méthodes de tests : nom à rallonge en camelCase ou avec des _ Messages d’erreur davantage explicite avec AssertJ que JUnit
  7. Qui dit test, dit jeux de données. Code existant difficilement testable ne respectant pas les principes OCP, LSP, KISS, ISP, DIP, SOLID (cf Clean Code)
  8. Exemple inspiré de la documentation Junit. Mais décomposition valable quelque soit la techno. Given When Then fait partie de la méthode agile Behavior-Driven Development http://martinfowler.com/bliki/GivenWhenThen.html Bonne pratique : séparer les blocs given/when/then par une ligne vide
  9. Mock = simulacre Les bouchons ne sont pas des simulacres : http://martinfowler.com/articles/mocksArentStubs.html Les mockes évitent de devoir coder des stubs et les maintenir (par exemple lors d’ajout de méthode dans une interface) Adhérences : DAO, autre service métier … Utilisation des mocks contestées Le NoMock Movement : http://antoniogoncalves.org/2012/11/27/launching-the-nomock-movement/ Mock ou pas Mock ? : https://www.fierdecoder.fr/2015/11/mock-ou-pas-mock/
  10. Autres outils non présentés : AssertJ, assertReflectionEquals pratique dans les cas suivant : Mapping objet / objet Marshalling / Unmarshalling Persistance / rechargement en base
  11. Introduction : Spring encourage le développement en utilisant des POJO. En principe, ceux-ci sont testables sans Spring. Cependant, il peut être tout de même intéressant de s’appuyer sur Spring pour : Profiter de l’injection de dépendance dans les tests, Tester unitairement la configuration Spring Réutiliser la configuration Spring Possibilité de ne pas utiliser le module spring test : création du contexte applicatif dans la méthode setUp Spring 4.2 supporte Junit 4.9 et + Mise en cache : pour tous les tests utilisant le même fichier de configuration Spring Demander à JUnit d’utiliser tel runner passe par l’annotation @RunWith (même principe utilisé par Unitils ou Mockito) Autres annotations : BeforeTransaction, AfterTransaction DirtiesContext : invalide le contexte afin que la prochaine méthode de test reconstruise le context Spring IfProfileValue : exécute un test en fonction de l’évaluation d’une variable système (ex: test spécifique à la plateforme) Autres bouchons : MockJspWriter, MockServletContext, MockPortletSession Spring MVC Test Framework : http://docs.spring.io/spring/docs/current/spring-framework-reference/html/integration-testing.html#spring-mvc-test-framework Les annotations @Sql, @SqlConfig et @SqlGroup ont été introduites dans Spring 4.1
  12. Alternative : DbSetup pour créer des jeux de données en Java
  13. Exemples issus de la documentation officielle : http://mockito.org/
  14. A la place du verify, privilégier plutôt assertEquals(admin, loadedUser); Performance : vérifier le nombre d’appel d’un WS
  15. Plus d’informations : http://www.baeldung.com/mockito-spy
  16. Exemple tiré du blog https://rwehner.wordpress.com/2010/02/23/mockito-some-useful-programming-examples/ D’autres exemples : http://www.programcreek.com/java-api-examples/org.mockito.ArgumentCaptor
  17. Base de données embarques : H2 ou HSQLDB DbUnit (XML) ou DbSetup (Java) Création du schéma : ResourceDatabasePopulator, @Sql, namespace <jdbc:initialize-database/> Gestion manuelle des transactions : TestTransaction Exécution du code en dehors des tx : @BeforeTransaction, @AfterTransaction
  18. Nécessite une surcouche technique. Exemple : Spring Test DbUnit https://github.com/springtestdbunit/spring-test-dbunit Dans cet exemple, la classe abstraite AbstractDaoTest est chargée de : Instancier le DAO à tester Initialiser la base de données embarquée Charger la configuration Hibernate Créer la table ACCOUNT La classe AbstractDaoTest utilise ou non Spring Test La classe DbUnitLoader factorise le code permettant de charger un dataset
  19. Classe de test inspiré de la classe ClinicServiceJpaTests du projet spring-petclinic La méthode assertThat vient de la librairie AssertJ http://joel-costigliola.github.io/assertj/ @Transactional : inutile de nettoyer la base après le test
  20. Extrait de spring-petclinic : https://github.com/spring-projects/spring-petclinic/blob/master/src/test/java/org/springframework/samples/petclinic/web/PetControllerTests.java