Le design pattern Data Driven Testing
Principe et avantages
Lors des tests fonctionnels, nous devons tester les interactions utilisateur relatives à la saisie de données. Ces interactions sont en général les plus importantes pour vérifier le bon comportement de notre application Web.
Jusqu’à présent, nous avons codé en dur les données que nos tests entrent dans les formulaires. Que se passe-t-il si un type de données change ou si son format change ? Nous devons parcourir nos classes et/ou nos scripts Pytest et modifier les valeurs de nos variables. C’est un long travail en termes de temps, ce n’est donc absolument pas productif en programmation et en maintenance.
Pour éliminer les longues heures de maintenance, pourquoi ne pas enregistrer les valeurs saisies lors des interactions utilisateur dans un endroit unique, facile d’accès et aisé à lire ?
C’est le principe du design pattern Data Driven Testing : stocker en dehors des programmes de test les valeurs qui seront utilisées pour simuler les interactions utilisateur et donc valider le comportement de notre application.
Nous pouvons utiliser le design pattern Data Driven Testing avec ou sans le design pattern Page Object Model car il ne concerne pas la modélisation des pages, mais juste le stockage des valeurs de test.
Comme le montre la figure ci-après, toutes les données texte et numériques...
Data Driven Testing avec POM et fichiers
Intégrons maintenant le design pattern Data Driven Testing dans notre application multipage sur laquelle nous travaillons depuis le chapitre Les waits pour une interaction optimale. Nos tests implémentent déjà le design pattern Page Object Model.
Les données que nous devons stocker pour tester cette application concernent le formulaire de la page d’accueil :
-
l’adresse électronique ;
-
le mot de passe ;
-
la civilité ;
-
le nom.
Formulaire de notre application de démonstration
Nous ajoutons dans notre script JavaScript une règle pour valider le mot de passe : il doit contenir entre sept et quatorze caractères, avec au moins un chiffre.
var passPattern = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{7,14}$/;
var password = document.getElementById('pass');
if(! password.value.match(passPattern)) {
// Changer la phrase par défaut du navigateur
txtErreur += "Le mot de passe n'est pas valide. ";
}
Notre jeu de données de test doit couvrir tous les cas possibles :
-
Toutes les entrées sont valides.
-
L’adresse de courriel n’est pas valide.
-
Le nom n’est pas valide.
-
La civilité est manquante.
-
Le mot de passe n’est pas valide.
Nous devons avoir deux jeux de test : un pour les données validant le formulaire et un deuxième pour celles qui ne permettent pas de valider le formulaire. En effet, nous devons tester deux comportements distincts avec deux fonctions de test différentes.
Nous prenons en compte dans nos tests la vérification de la politique de mot de passe en vérifiant qu’un mot de passe sans chiffre ou trop petit ou tout simplement manquant ne validera pas le formulaire.
Nous pouvons maintenant simplifier le comportement de notre classe contenant le formulaire, les données étant fournies par les tests :
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import...
Data Driven Testing et BD
Commençons par créer une base de données testdatas pour enregistrer notre jeu de données de test. Au sein de cette base, nous allons créer une table formdatas et les colonnes nécessaires pour enregistrer un identifiant, une adresse électronique, un mot de passe, une civilité, un nom et un booléen pour indiquer si les données valident ou non le formulaire.
CREATE SCHEMA `testdatas` ;
CREATE TABLE `testdatas`.`formdatas` (
`iddata` INT NOT NULL AUTO_INCREMENT,
`email` VARCHAR(255) NULL,
`pass` VARCHAR(45) NULL,
`civilite` VARCHAR(45) NULL,
`name` VARCHAR(45) NULL,
`valide` TINYINT NULL,
PRIMARY KEY (`iddata`));
Insérons maintenant notre jeu de données de test dans la table formdatas.
INSERT INTO `testdatas`.`formdatas` (`email`, `pass`, `civilite`,
`name`, `valide`) VALUES ('ludi@ludi.fr', 'Azerty8', 'mme',
'Ludivine', '1');
INSERT INTO `testdatas`.`formdatas` (`pass`, `civilite`, `name`,
`valide`) VALUES ('Azerty8', 'mme', 'Ludivine', '0');
INSERT INTO `testdatas`.`formdatas` (`email`, `pass`, `valide`)
VALUES ('ludi@ludi.fr', 'Azerty8', '0');
INSERT INTO `testdatas`.`formdatas` (`email`, `pass`, `civilite`,
`name`, `valide`) VALUES ('ludi@ludi.fr', 'Azerty8', '',
'Ludivine', '0');
INSERT INTO `testdatas`.`formdatas` (`email`, `pass`, `civilite`,
`name`, `valide`) VALUES ('ludi@ludi.fr', 'Azer8'...
Data Driven Testing sans POM
Nous fournissons dans cette section un test fonctionnel avec le design pattern Data Driven Testing sans le design pattern Page Object Model pour le lecteur qui ne veut pas implémenter de design pattern. Notre démarche reste la même, nous chargeons au début notre jeu de données de test qui sera fourni aux fonctions de test liées au formulaire.
Nous stockons nos données de test dans un fichier CSV.
import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
import csv
def initData(file) :
with open(file) as csvFile:
csv_reader = csv.reader(csvFile, delimiter=',')
datas = []
entete = True
for data in csv_reader :
if entete :
entete = False
else :
datas.append([data[0], data[1], data[2],
data[3]])
print(datas)
return datas
dataNop = initData('dataFormulaireConnexionNop.csv')...
Exercice
Ajoutez le design pattern Data Driven Testing aux tests de l’exercice du chapitre Le design pattern Page Object Model, afin d’avoir des tests complets respectant toutes les bonnes pratiques. Choisissez le support de stockage le plus intéressant pour vous.