Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Python e strumenti per il testing

Python e strumenti per il testing delle applicazioni Web. Due casi pratici basati sull'analisi di un tastierino numerico
Python e strumenti per il testing delle applicazioni Web. Due casi pratici basati sull'analisi di un tastierino numerico
Link copiato negli appunti

Esistono vari modi in Python per eseguire test e sono applicabili non solo al caso delle interfacce web ma a qualsiasi altra attività applicativa. Qui ne vedremo due ma opportune ricerche su documentazione e motori di ricerca dimostreranno che esistono molte altre alternative.

Li sperimenteremo trasformando in test le operazioni che abbiamo svolto con Selenium su un tastierino numerico web di cui riportiamo qui di seguito per comodità il codice HTML e JavaScript:

<!DOCTYPE html>
<html>
<head>
	<title>Tastierino Numerico</title>
	<style>
		table {
		  width: auto;
		  margin: auto;
		}
		td {
		  text-align: center;
		}
    .da0a9{
        height:70px;
        width:70px;
    }
    .rigaintera{
        height: 50px;
        width: 200px;
        text-align: right;
    }
	</style>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
</head>
<body>
	<table>
    <tr>
      <td colspan="3"><input class="rigaintera" id="display" readonly></td>
    </tr>
		<tr>
			<td><button class="da0a9">1</button></td>
			<td><button class="da0a9">2</button></td>
			<td><button class="da0a9">3</button></td>
		</tr>
		<tr>
			<td><button class="da0a9">4</button></td>
			<td><button class="da0a9">5</button></td>
			<td><button class="da0a9">6</button></td>
		</tr>
		<tr>
			<td><button class="da0a9">7</button></td>
			<td><button class="da0a9">8</button></td>
			<td><button class="da0a9">9</button></td>
		</tr>
		<tr>
			<td colspan="3"><button class="da0a9">0</button></td>
		</tr>
	</table>
    <script>
      $(document).ready(function () {
          $('button').click(function () {
		      $( "#display" ).val( $( "#display" ).val() +$(this).text() );
          });
      });
  </script>
</body>
</html>

Per entrambe le modalità che vedremo svolgeremo due test:

  • uno verificherà che il valore restituito dal display vuoto sia una stringa;
  • l'altro consisterà nella verifica della corretta digitazione automatica di una sequenza decisa a priori (la stessa operazione svolta nell'esempio della lezione in cui abbiamo presentato il tastierino).

Usare gli assert di Python

La prima modalità sfrutta la parola chiave assert. Questa è molto nota ed utilizzata dai programmatori Python e riceve come argomento un'operazione da svolgere che restituisca un valore booleano. Se questa avrà come risultato true non succederà niente, altrimenti verrà lanciato un errore di tipo AssertionError eventualmente gestibile con un costrutto try...except. Si potrà anche passare un ulteriore parametro che indicherà, in caso di errore, il messaggio da riportare.

Se tutti gli assert che abbiamo predisposto nei test non avranno causato errori, la nostra applicazione avrà superato l'intera batteria di prove.

Per creare un test con gli assert non faremo altro che creare una sequenza di funzioni in ognuna delle quali avvieremo una sessione driver completa e alla fine del codice metteremo un assert in cui dovremo cercare di svolgere un test adatto a confermare la nostra ipotesi di esecuzione.

from selenium import webdriver
from selenium.webdriver.common.by import By
def test_tipo_display():
    driver = webdriver.Chrome()
    driver.get('http://localhost/tastierino.html')
    # verifica del tipo di valore del campo diplay
    assert isinstance(driver.find_element(By.XPATH,f'//input[@id="display"]').get_attribute('value'), str)
    print("Test TIPO DISPLAY eseguito: OK")
    driver.quit()
def test_tastierino():
    driver = webdriver.Chrome()
    driver.get('http://localhost/tastierino.html')
    #sequenza per la sperimentazione
    sequenza='78935627'
    # leggiamo la sequenza un carattere alla volta
    for carattere in sequenza:
        # con XPath individuiamo il pulsante e lo clicchiamo
        driver.find_element(By.XPATH,f'//button[normalize-space()="{carattere}"]').click()
    # verifichiamo che la sequenza che appare a display sia quella desiderata
    assert driver.find_element(By.XPATH,f'//input[@id="display"]').get_attribute('value')==sequenza
    print("Test DIGITAZIONE SEQUENZA eseguito: OK")
    driver.quit()
test_tipo_display()
test_tastierino()

Le funzioni

Come si vede abbiamo creato due funzioni in ognuna delle quali l'ipotesi da verificare è stata trasformata in un confronto in modo da poterlo valutare con un assert. Rispetto agli esempi delle lezioni precedenti, notiamo che in ogni funzione viene messo al lavoro Selenium per azionare l'interfaccia ma si finisce sempre a svolgere un confronto che possa essere valutato con un assert.

Nel primo caso, si verifica che il display (individuato con //input[@id="display"]) sia un'istanza, isinstance, della classe str.

Nel secondo recuperiamo il valore del display e controlliamo che sia uguale alla stringa sequenza. Si ricordi che se uno dei test fallisce, l'errore di tipo AssertionError prodotto fermerà il programma e non farà eseguire gli altri test. Pertanto, con questo approccio, si inseriscano dove si preferisce dei controlli try...except per gestire opportunamente esecuzione e reportistica delle prove.

Creazione di unit test

Come seconda modalità, vedremo la libreria unittest, già presente nell'installazione del linguaggio. Come indica il suo nome, è pensata per test unitari sebbene la si possa sfruttare per test più complessi, di integrazione, cosa che faremo nelle prossime lezioni. Tuttavia, si tenga sempre presente che il mondo Python è pienissimo di alternative interessanti a questi strumenti.

Come mostra il codice che segue, unittest può essere vista come una sorta di strutturazione più rigida del meccanismo degli assert infatti dovremo:

  • creare una classe derivante da unittest.TestCase. Questa rappresenterà il nostro test case ovvero l'insieme di test da avviare;
  • predisporre una funzione per ogni test che nel nostro caso saranno due. Si noti che ogni test termina con la chiamata ad un metodo che deriva proprio da assert. Qui useremo assertEqual per verificare l'uguaglianza e assertIsInstance per dimostrare l'appartenenza ad una specifica classe di un valore. Esiste una lista completa dei metodi assert* esistenti nella documentazione ufficiale;
  • preparare un metodo setUp per l'inizializzazione del test il quale verrà eseguito prima di ogni test;
  • definire un metodo tearDown per la finalizzazione del test che sarà eseguito alla fine di ogni test;
  • avviare il testcase mediante invocazione del metodo main.

Il test con Python

Questo il nostro test:

from selenium import webdriver
from selenium.webdriver.common.by import By
import unittest
class Testing(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.get('http://localhost/tastierino.html')
    def test_display(self):
        self.assertIsInstance(self.driver.find_element(By.XPATH,f'//input[@id="display"]').get_attribute('value'), str)
    def test_tastierino(self):
        # sequenza per la sperimentazione
        sequenza='78935627'
        # leggiamo la sequenza un carattere alla volta
        for carattere in sequenza:
            # con XPath individuiamo il pulsante e lo clicchiamo
            self.driver.find_element(By.XPATH,f'//button[normalize-space()="{carattere}"]').click()
        # verifichiamo che la sequenza che appare a display sia quella desiderata
        self.assertEqual(self.driver.find_element(By.XPATH,f'//input[@id="display"]').get_attribute('value'),sequenza)
    def tearDown(self):
        self.driver.quit()
if __name__ == '__main__':
    unittest.main()

Come vedremo sperimentandolo, in questo approccio tutti i test saranno comunque eseguiti, anche in caso di fallimento, e alla fine - oltre ad una dettagliata descrizione di errore - ci verrà fornito un responso sintetico come:

Ran 2 tests in 19.010s
OK

in caso di successo di tutti i test, oppure:

Ran 2 tests in 14.788s
FAILED (failures=1)

che ci notificherà il fallimento totale o parziale del test case e ci indicherà quanti sono i test falliti (abbiamo provocato volutamente il fallimento del secondo test provando una sequenza sbagliata).

I metodi setUp e tearDown sono stati usati, rispettivamente, per avviare il driver e chiuderlo in modo da avere punti unitari in cui concentrare tali operazioni comuni a tutti i test.

Soprattutto in fase di apprendimento di questi strumenti non si esiti a fare uso di istruzioni print per stampare messaggi in modo da arricchire la reportistica prodotta e seguire bene il procedere dell'esecuzione.

Ti consigliamo anche