Nous avons appris dans la partie 2 que nous pouvions contrôler de manière simple Firefox OS en utilisant les commandes du client Marionette. Néanmoins, les saisir dans une console Python est aussi lent que fastidieux. L'avantage clé de l'automatisation de tests est son exécution autonome. Nous allons apprendre comment faire cela dans cette partie, en mettant toutes nos commandes dans un fichier Python qui pourra s'exécuter d'un seul coup.
Résumé d'un cas de test
Dans la partie 2, nous avons passé les étapes pour exécuter un cas de test typique — ouvrir l'application Contacts et ajouter un nouveau contact :
- Déverrouiller Firefox OS (facultatif ; dans la partie 2 nous avons désactivé l'écran de verrouillage manuellement, en conséquence nous ne l'incluerons pas dans le code ci-dessous)
- Aller dans l'application Contacts
- Appuyer sur l'icône d'ajout d'un nouveau contact
- Saisir le nom du contact
- Appuyer sur OK
- Attendre et vérifier que le contact est présent
Mettre notre test dans un fichier Python
Si nous mettons toutes ces étapes dans un fichier Python, nous pouvons le réutiliser et l'exécuter bien plus rapidement. Créez un nouveau fichier texte nommé test_add_contact.py
dans un dossier convenable de votre choix.
Dans ce fichier, entrez les commandes que nous avons vues dans la partie 2, comme listé ci-dessous. Nous utiliserons une structure de classes Python, puisque c'est une bonne pratique et qui plus est elle constitue une bonne base pour construire les étapes à venir de ce tutoriel.
import time from marionette import Marionette class TestContacts: def __init__(self): self.test_add_contacts() def test_add_contacts(self): # Create the client for this session. Assuming you're using the default port on a Marionette instance running locally self.marionette = Marionette() self.marionette.start_session() # Switch context to the homescreen iframe and tap on the contacts icon time.sleep(2) home_frame = self.marionette.find_element('css selector', 'div.homescreen iframe') self.marionette.switch_to_frame(home_frame) contacts_icon = self.marionette.find_element('xpath', "//div[@class='icon']//span[contains(text(),'Contacts')]") contacts_icon.tap() # Switch context back to the base frame self.marionette.switch_to_frame() time.sleep(2) # Switch context to the contacts app contacts_frame = self.marionette.find_element('css selector', "iframe[data-url*='contacts']") self.marionette.switch_to_frame(contacts_frame) # Tap [+] to add a new Contact self.marionette.find_element('id', 'add-contact-button').tap() time.sleep(2) # Type name into the fields self.marionette.find_element('id', 'givenName').send_keys('John') self.marionette.find_element('id', 'familyName').send_keys('Doe') # Tap done self.marionette.find_element('id', 'save-button').tap() time.sleep(2) # Close the Marionette session now that the test is finished self.marionette.delete_session() if __name__ == '__main__': TestContacts()
Note : il y a une chose que vous allez remarquer dans le code que nous n'avons pas couverte dans la partie 2 : la fonction Python time.sleep()
— cela met le script en pause pour une certaine durée (définie en secondes) avant qu'il ne continue jusqu'à la ligne suivante. Nous avons ajouté ces lignes dans le test automatisé car nous devons simuler l'utilisateur qui, manuellement, appuie sur les boutons, etc. et attendre que Firefox OS effectue les actions qui en résultent. Si nous exécutons le script sans pause, Python effectuera toutes les actions de manière instantanée, mettant probablement le test en échec, puisque Firefox OS n'aurait pas été capable de s'adapter.
À présent, nous pouvons lancer le test en allant dans le fichier où le test est enregistré via le terminal et en exécutant la commande suivante :
python test_add_contact.py
Note : soyez vigilant par rapport aux règles d'identation de Python. Après avoir copié et collé le code vous devrez probablement tout identer correctement pour qu'il s'exécute. Si vous obtenez une erreur liée à ce point, assurez-vous que tous les niveaux d'indentation sont séparés par une tabulation.
Note : vous remarquerez également que le nom inséré dans le code ci-dessus est "John Doe", à la différence du nom "Foo Bar" de la partie 2. Nous avons fait ce changement dans le code pour qu'il puisse ajouter avec succès un autre contact. Si vous essayez d'ajouter un contact avec le même nom, Firefox OS vous alertera sur le doublon de contacts. Pour l'instant, la meilleure façon de répéter l'exécution du test est d'aller dans l'interface de Firefox OS et de supprimer manuellement le contact avant chaque exécution.
Ajouter une assertion
L'élément qui manque toujours dans notre test, qui est important dans les tests automatisés, est une assertion — un rapport ou mesure pour déterminer si Firefox OS a atteint l'état que nous voulions qu'il atteigne ou si le test est un succès. Nous allons régler ce problème en ajoutant du code pour vérifier si le nouveau contact est présent dans l'application.
Juste avant la ligne # Close the Marionette session…
ajoutez dans ce code, en s'assurant qu'il est indenté au même niveau que les autres lignes de la classe :
# Now let's find the contact item and get its text contact_name = self.marionette.find_element('css selector', 'li.contact-item:not([data-group$="ice"]) p').text assert contact_name == 'John Doe'
Supprimez l'ancien contact et essayer d'exécuter de nouveau le test, avec la commande suivante :
python test_add_contact.py
Si cela s'exécute correctement, alors nous avons un test qui fonctionne !
Note : si l'assertion échoue, assurez-vous que le précédent contact 'Foo Bar' n'existe plus. Le sélecteur CSS avant l'assertion prend en compte le premier contact de la liste (cela pourrait être visible en appelant print "Contact name: %s" % contact_name
avant l'appel de l'assertion).
Note : l'assertion n'apparaîtra pas pour faire quelque chose, mais les assertions sont très importantes quand nous commençons à utiliser des exécuteurs de tests, comme présenté dans la Partie 5: Présentation d'un exécuteur de tests. Les exécuteurs de test comme unittest utilisent les assertions pour vérifier si les tests ont été réalisés avec succès ou non, et ensuite retournent les résultats de ces tests (OK ou FAIL.)
Note sur le timing
Une des choses les plus difficiles à gérer en écrivant un test automatisé est le timing. Si le test passe à l'étape suivant avant que Firefox OS n'effectue la précédente, alors nous allons probablement avoir un échec du test.
Comme mentionné ci-dessus, dans l'exemple de code que nous avons ajouté, la commande time.sleep(x)
résout ce problème. Pourtant, utiliser time.sleep(x)
n'est pas une bonne pratique. Utiliser une temporisation codée en dur peut faire que le test va s'exécuter trop longtemps ou pas assez. Le dernier cas est le pire ; il donnera des résultats de tests faux négatifs — ce qui signifie un test qui remonte un échec quand en réalité l'application fonctionne parfaitement mais se comporte de manière plus lente que ce que le test espérait.
Dans la partie suivante, nous aborderons l'abstraction de certains points du test vers des fonctions Pythons distinctes, et remplacerons les fonctions sleep()
par les temporisations dynamiques appropriées.