User story et tests fonctionnels

Un test fonctionnel un peu plus riche fondé sur une User Story

Le test suivant utilise un LiveServerTestCase ou un StaticLiveServerTestCase pour que le test puisse accéder au serveur normalement lancé (et avec toutes les ressources statiques si besoin). Plaçons le dans le fichier tests.py de notre app myform :

    from django.test import TestCase

# Create your tests here.
from selenium import webdriver
from selenium.webdriver.common.by import By
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
#from django.test import LiveServerTestCase
#from selenium.webdriver.chrome.options import Options
from selenium.webdriver.firefox.options import Options
#from selenium.webdriver.firefox.webdriver import WebDriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from time import time
import re

class FunctionalTest(StaticLiveServerTestCase):
    #fixtures = ['user-data.json']

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.options = Options()
        cls.options.add_argument("--headless")
        cls.browser = webdriver.Firefox(options=cls.options)
        #cls.browser = webdriver.Chrome(executable_path='/usr/bin/chromedriver',options=cls.options)
        print("Webdriver loaded")
        cls.browser.implicitly_wait(3)

    @classmethod
    def tearDownClass(cls):
        cls.browser.quit()
        super().tearDownClass()

    def test_can_show_creation_form(self):
        # Alice se rend sur le site localhost:8000/contacts/
        # et compte y trouver une app de gestion des contacts
        # avec un formulaire de création
        self.browser.get('%s%s' % (self.live_server_url, '/contacts/'))
        self.browser.implicitly_wait(3)
        # Elle remarque que le mot "Contact"
        # figure dans le titre de la page
        self.assertIn('Contact', self.browser.title)
        #self.fail('Test terminé !')

        # Elle peut aussi créer ce contact ...
        # Puis constater qu'il figure bien
        # dans la page qui liste les contacts ...


    def test_can_add_and_del_contact(self):
        '''Test d'ajout et supression d'un contact '''

        # Alice se rend sur la route de création
        # d'un nouveau contact
        print(self.live_server_url)
        self.browser.get(self.live_server_url+'/contacts/')
        self.browser.implicitly_wait(3)
        # Elle crée un nouveau contact appelé  "Al" "Ouette"
        # Ayant pour mail "al@ouette.org"
        # Avec le message "Lorem ipsum dolor sit amet."
        name = self.browser.find_element(By.ID, "id_name")
        firstname = self.browser.find_element(By.ID,"id_firstname")
        message = self.browser.find_element(By.ID, "id_message")
        email = self.browser.find_element(By.ID,"id_email")
        # Elle envoie son nom, prénom
        name.send_keys("Ouette")
        self.browser.implicitly_wait(1)
        firstname.send_keys("Al")
        self.browser.implicitly_wait(1)
        # puis son email
        email.send_keys("al@ouette.org")
        self.browser.implicitly_wait(1)
        ## Elle crée un message
        message.send_keys("Lorem ipsum dolor sit amet ...")
        self.browser.implicitly_wait(1)

        ## Alice valide le formulaire
        # On peut attendre la localisation de l'élément mais pas solide
        # Il vaut mieux utiliser un driver 'headless' comme ici
        # WebDriverWait(self.browser, 20).until(EC.presence_of_element_located((By.ID, "submit"))).click()
        self.browser.find_element(By.ID,"submit").click()
        self.browser.implicitly_wait(5)

        #Le contact doit à présent être créé si tout s'est bien passé
        # Ajuster à votre CSS

        title = self.browser.find_element(By.CSS_SELECTOR, ".jumbotron > h2:nth-child(1)")
        self.browser.implicitly_wait(1)
        contactFound = "Ouette" in title.text

        #on vérifie si le contact a bien été trouvé
        self.assertEqual(True,contactFound)

        #à présent Alice va cliquer pour afficher les détails du contact
        #elem.click()
        self.browser.implicitly_wait(1)
        #Puis sélectionner l'icone de suppression pour supprimer le contact
        # Ajuster à votre CSS
        #self.browser.find_element(By.CSS_SELECTOR,"body > div > section.content-header > a:nth-child(1) > i").click()


        #on verifie que le contact est bien supprimé
        # Ajuster à votre CSS
        #noms = self.browser.find_element(By.CSS_SELECTOR,"body  > div > section.content-header > div > div > div.box-header > a > h4")
        #contactFound = False
        #for nom in noms:
        #    if re.match("Ouette", nom.text):
        #        contactFound = True
        #self.assertEqual(False,contactFound)

Pour tester, si besoin (si vous passez habituellement par un proxy), ajoutez une variable no_proxy :

# Si besoin
export no_proxy=127.0.0.1, localhost

Couverture par les tests

Pour connaitre plus précisément la couverture par les tests de notre application, il est possible d’installer coverage.py comme documenté ici.