Automatiser les tests
d’acceptation :
Comment s’y prendre ?
Vincent Tencé
@testinfected
http://vtence.com
http://github.co...
Terminé ?
Livraison habituelle stress inclus
Livraison souhaitée sourire inclus
Les tests clients sont
essentiels
à une livraison réussie
Test d’acceptation de bout en bout
Persistence
Time
UserInterface
Mail
Payment
Test
Tests instables
• Échouent de façon imprévisible

• Dépendent d’un jeu unique et vivant de données de test

• Dépendent de...
Visez l’atomicité
• Partez d’un état initial connu minimal

• Utilisez le jeu de données minimal suffisant pour le scénario ...
Utilisez vos API
public void registerUser(String email, String password) {

HttpResponse response =
request.content(Form.u...
Waits
WebDriver driver = new FirefoxDriver();
driver.get(“http://some_domain/url_that_delays_login”);
WebDriverWait wait =...
Acceptez l’asynchronisme
BrowserDriver browser = new BrowserDriver(
new UnsynchronizedProber(2000, 50),
new FirefoxDriver(...
Manque d’abstraction
DesiredCapabilities capabilities = DesiredCapabilities.firefox();

WebDriver driver = new FirefoxDriv...
Trop de détails
Scenario: Successful login


Given a user "Bob" with password "secret"

And I am on the login page
# Ces l...
Page Objects
DesiredCapabilities capabilities = DesiredCapabilities.firefox();

WebDriver driver = new FirefoxDriver(capab...
Tests liés aux conditions d’acceptation
Scenario: Successful login


Given the user "Bob" has registered
When he logs in s...
Tests des récits utilisateurs
• Mènent à un trop grand nombre de tests

• Créent une batterie de tests difficile à maintenir...
Testez les parcours utilisateurs
• Testez les interactions complètes d’un utilisateur avec le système 

en vue de l’attein...
Ne cherchez pas à être exhaustif
@Test

public void joinsToGetPremiumFeaturesBySelectingAPayingPlan() {

Join registration...
Pensez comme des utilisateurs
• Rôles : Qui ?

• Objectifs : Pour quoi ?
• Activités et tâches : Quoi ?

• Actions : Comme...
Acteurs
// Plusieurs acteurs vont collaborer
Actors actors = new Actors(config);
// Un acteur initialement anonyme, avec u...
Objectifs
// Les objectifs des utilisateurs s’expriment dans les noms des
// classes de test et des scénarios de test
publ...
Activités et tâches
// Les tâches sont groupées en activités auxquelles
// les acteurs participent
public class Join {

pu...
Actions
// Les acteurs interagissent avec des éléments de l’interface
// utilisateur pour accomplir leurs tâches
public cl...
Évaluations
// Les interactions ont des conséquences que les acteurs
// vont évaluer en posant des questions
public class ...
Au final
@Test

public void joinsToGetPremiumFeaturesBySelectingAPayingPlan() {

Join registration = anonymous.signUp().as(...
En incluant les acteurs externes
@Test

public void joinsAndSelectsAPayingPlan() throws Exception {

Join registration = a...
À vous de jouer !
• Acceptez la nature asynchrone du Web

• Écrivez des tests atomiques

• Testez les parcours utilisateur...
Automatiser les tests d'acceptation : comment s'y prendre ?
Automatiser les tests d'acceptation : comment s'y prendre ?
Automatiser les tests d'acceptation : comment s'y prendre ?
Prochain SlideShare
Chargement dans…5
×

Automatiser les tests d'acceptation : comment s'y prendre ?

147 vues

Publié le

Session présentée à Agile Tour Montréal 2016

Si vous rencontrez des défis dans l’automatisation de vos tests d’acceptation ou si vous vous posez des questions sur la meilleure marche à suivre, cette séance est pour vous.

Découvrez comment mettre en place une batterie de tests d’acceptation utile et pérenne en ayant du plaisir à le faire. Attention, code en vue !

Publié dans : Logiciels
  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

Automatiser les tests d'acceptation : comment s'y prendre ?

  1. 1. Automatiser les tests d’acceptation : Comment s’y prendre ? Vincent Tencé @testinfected http://vtence.com http://github.com/testinfected
  2. 2. Terminé ?
  3. 3. Livraison habituelle stress inclus
  4. 4. Livraison souhaitée sourire inclus
  5. 5. Les tests clients sont essentiels à une livraison réussie
  6. 6. Test d’acceptation de bout en bout Persistence Time UserInterface Mail Payment Test
  7. 7. Tests instables • Échouent de façon imprévisible • Dépendent d’un jeu unique et vivant de données de test • Dépendent de systèmes externes hors de notre contrôle • Gèrent mal la nature asynchrone du Web
  8. 8. Visez l’atomicité • Partez d’un état initial connu minimal • Utilisez le jeu de données minimal suffisant pour le scénario décrit • Nettoyez avant plutôt qu’après • Remplacez les systèmes externes par des « faux » qui sont programmables et que vous contrôlez
  9. 9. Utilisez vos API public void registerUser(String email, String password) {
 HttpResponse response = request.content(Form.urlEncoded() .addField("email", email)
 .addField("password", password)
 .addField("conditions", "on"))
 .post("/accounts");
 // Pour améliorer le diagnostique du test
 assertThat(response).hasStatusCode(303); }

  10. 10. Waits WebDriver driver = new FirefoxDriver(); driver.get(“http://some_domain/url_that_delays_login”); WebDriverWait wait = new WebDriverWait(driver, 2, 50); WebElement display = wait.until(presenceOfElementLocated( By.id("some-dynamic-element"))); assertThat("display text", display.getText(), equalTo("Loaded")) WebElement button = wait.until(elementToBeClickable( By.id(“some-button"))); button.click();
  11. 11. Acceptez l’asynchronisme BrowserDriver browser = new BrowserDriver( new UnsynchronizedProber(2000, 50), new FirefoxDriver()); browser.navigate().to(“http://somedomain/url_that_delays_loading"); browser.element(By.id(“some-dynamic-element")).hasText("Loaded"); browser.element(By.id(“some-button”)).click(); java.lang.AssertionError: Tried to: check that an element by id "some-button" is enabled but: it was disabled
  12. 12. Manque d’abstraction DesiredCapabilities capabilities = DesiredCapabilities.firefox();
 WebDriver driver = new FirefoxDriver(capabilities);
 
 // Enter username and password
 driver.findElement(By.id("username")).sendKeys("Bob");
 driver.findElement(By.id("password")).sendKeys("secret");
 
 // Click login button
 driver.findElement(By.id("login")).submit();
 
 // Wait for home page to load
 WebDriverWait wait = new WebDriverWait(driver, 5000); wait.until(ExpectedConditions.titleIs("Home")); 
 // Check the greeting message String greeting = driver.findElement(By.id("greeting")).getText();
 assertThat(greeting, equalTo("Welcome, Bob!"));
  13. 13. Trop de détails Scenario: Successful login 
 Given a user "Bob" with password "secret"
 And I am on the login page # Ces lignes là vont toujours ensemble
 And I fill in "Username" with "Bob"
 And I fill in "Password" with "secret" # J’ai vraiment besoin de connaître tous ces détails ?
 When I press "Log In" 
 Then I should see "Welcome, Bob!"
  14. 14. Page Objects DesiredCapabilities capabilities = DesiredCapabilities.firefox();
 WebDriver driver = new FirefoxDriver(capabilities);
 // Euh, vraiment ? LogInPage loginPage = PageFactory.initElements(driver, LogInPage.class);
 
 // Voilà la partie intéressante HomePage page = loginPage.loginAs("Bob", "secret"); // Et si l’affichage est asynchrone ? assertThat(page.greetingMessage(), equalTo("Welcome, Bob!"));
  15. 15. Tests liés aux conditions d’acceptation Scenario: Successful login 
 Given the user "Bob" has registered When he logs in successfully Then he should see "Welcome, Bob!"
  16. 16. Tests des récits utilisateurs • Mènent à un trop grand nombre de tests • Créent une batterie de tests difficile à maintenir • Diminuent la valeurs des tests d’acceptation comme source de documentation fonctionnelle • Ne renseignent pas sur la valeur disponible aux utilisateurs
  17. 17. Testez les parcours utilisateurs • Testez les interactions complètes d’un utilisateur avec le système 
 en vue de l’atteinte d’un objectif donné • Utilisez un petit nombre de tests de parcours utilisateurs seulement 
 pour tester l’intégration de l’ensemble du système
  18. 18. Ne cherchez pas à être exhaustif @Test
 public void joinsToGetPremiumFeaturesBySelectingAPayingPlan() {
 Join registration = anonymous.signUp().as(bob());
 
 User bob = registration.selectPayingPlan("micro")
 .enterBillingDetails("5555555555554444", "12/18", "999"); 
 bob.manageAccount()
 .showsCurrentlyOnPlan("micro")
 .seesCreditCardDetails("**** **** **** 4444", "12/18");
 }

  19. 19. Pensez comme des utilisateurs • Rôles : Qui ? • Objectifs : Pour quoi ? • Activités et tâches : Quoi ? • Actions : Comment ? • Évaluations : Conséquences ?
  20. 20. Acteurs // Plusieurs acteurs vont collaborer Actors actors = new Actors(config); // Un acteur initialement anonyme, avec un rôle de visiteur
 User anonymous = actors.visitor(); // Les systèmes externes aussi sont des acteurs importants
 RemoteApplication api = actors.remoteApplication();

  21. 21. Objectifs // Les objectifs des utilisateurs s’expriment dans les noms des // classes de test et des scénarios de test public class JoiningTheCommunityTest {
 @Test
 public void joinsToLearnMoreBySelectingAFreePlan() { … } @Test
 public void joinsToGetPremiumFeaturesBySelectingAPayingPlan() { … } }
  22. 22. Activités et tâches // Les tâches sont groupées en activités auxquelles // les acteurs participent public class Join {
 public Join signUp() { … }
 
 public Join as(AccountDetails details) { screen.enterEmail(details.email) .enterPassword(details.password) .acceptConditions() .signUp(); } 
 public User chooseFreePlan() { … } 
 
 public Join selectPayingPlan(String name) { … } 
 … }
  23. 23. Actions // Les acteurs interagissent avec des éléments de l’interface // utilisateur pour accomplir leurs tâches public class SignUpScreen { 
 public SignUpScreen enterEmail(String email) {
 browser.element( id("sign-up")).element(id("email")).type(email); return this; }
 public SignUpScreen enterPassword(String password) {
 browser.element( id("sign-up")).element(id("password")).type(password); return this; }
 … }
  24. 24. Évaluations // Les interactions ont des conséquences que les acteurs // vont évaluer en posant des questions public class BillingScreen {
 
 public BillingScreen showsCurrentPlan(String planName) {
 browser.element(By.id("plan")) .hasText(containsStringIgnoringCase(planName));
 return this;
 }
 
 public BillingScreen showsCurrentCardDetails(String description, String validity) {
 browser.element(By.id("payment")) .hasText(containsStringIgnoringCase(description));
 browser.element(By.id("payment")) .hasText(containsStringIgnoringCase(validity));
 return this;
 }
 }
  25. 25. Au final @Test
 public void joinsToGetPremiumFeaturesBySelectingAPayingPlan() {
 Join registration = anonymous.signUp().as(bob());
 
 User bob = registration.selectPayingPlan("micro")
 .enterBillingDetails("5555555555554444", "12/18", "999"); 
 bob.manageAccount()
 .showsCurrentlyOnPlan("micro")
 .seesCreditCardDetails("**** **** **** 4444", "12/18");
 }

  26. 26. En incluant les acteurs externes @Test
 public void joinsAndSelectsAPayingPlan() throws Exception {
 Join registration = anonymous.signUp().as(bob()); paymentGateway.hasCreatedCustomerAccount(bob().email), "free");
 mailServer.hasSentWelcomeEmailTo(bob().email); 
 User bob = registration.selectPayingPlan("micro")
 .enterBillingDetails("5555555555554444", "12/18", "999"); paymentGateway.hasCreatedCreditCard(bob().email, "5555555555554444", "12/18","999")
 .hasUpgradedCustomerPlan(bob().email, "micro"); 
 bob.manageAccount()
 .showsCurrentlyOnPlan("micro")
 .seesCreditCardDetails("**** **** **** 4444", "12/18");
 }

  27. 27. À vous de jouer ! • Acceptez la nature asynchrone du Web • Écrivez des tests atomiques • Testez les parcours utilisateurs • Pensez comme des utilisateurs

×