Il test delle unità consente di verificare la qualità del codice dopo averlo scritto, ma puoi anche utilizzare il test delle unità per migliorare il processo di sviluppo man mano che procedi. Anziché scrivere i test al termine dello sviluppo dell'applicazione, puoi scriverli man mano che procedi. In questo modo, puoi progettare piccole unità di codice riutilizzabili e gestibili. Inoltre, semplifica il test completo e rapido del codice.
Quando esegui i test delle unità locali, esegui test che rimangono all'interno del tuo ambiente di sviluppo senza coinvolgere componenti remoti. App Engine fornisce utilità di test che utilizzano implementazioni locali di datastore e altri servizi App Engine. Ciò significa che è possibile esercitare l'utilizzo di questi servizi da parte del codice localmente, senza eseguire il deployment del codice in App Engine, tramite stub di servizio.
Uno stub di servizio è un metodo che simula il comportamento del servizio. Ad esempio, lo stub del servizio datastore mostrato in Scrittura di test di datastore e Memcache consente di testare il codice del datastore senza effettuare richieste al datastore reale. Qualsiasi entità archiviata durante il test delle unità del datastore viene conservata in memoria, non nell'archivio dati, e viene eliminata dopo l'esecuzione del test. Puoi eseguire test rapidi e di piccole dimensioni senza alcuna dipendenza dal datastore.
Questo documento descrive come scrivere i test delle unità rispetto a diversi servizi App Engine locali, quindi fornisce alcune informazioni sulla configurazione di un framework di test.
Introduzione alle utilità di test di Python 2
Un modulo Python di App Engine denominato testbed
rende disponibili gli stub di servizio per il test delle unità.
Gli stub di servizio sono disponibili per i seguenti servizi:
- Identità app
init_app_identity_stub
- Archivio BLOB (utilizza
init_blobstore_stub
) - Capacità (utilizza
init_capability_stub
) - Datastore (utilizza
init_datastore_v3_stub
) - File (utilizza
init_files_stub
) - Immagini (solo per
dev_appserver;
utilizza
init_images_stub
) - LogService (utilizza
init_logservice_stub
) - Posta (utilizza
init_mail_stub
) - Memcache (utilizza
init_memcache_stub
) - Coda di attività (utilizza
init_taskqueue_stub
) - Recupero URL (utilizza
init_urlfetch_stub
) - Servizio utenti (utilizza
init_user_stub
)
Per inizializzare tutti gli stub contemporaneamente, puoi utilizzare init_all_stubs
.
Scrittura di test Datastore e memcache
Questa sezione mostra un esempio di come scrivere codice che verifica l'utilizzo dei servizi datastore e memcache.
Assicurati che l'esecutore del test disponga delle librerie appropriate nel percorso di caricamento Python, incluse le librerie di App Engine, yaml
(incluse nell'SDK di App Engine), la radice dell'applicazione ed eventuali altre modifiche al percorso della libreria previste dal codice dell'applicazione (ad esempio una directory ./lib
locale, se disponibile). Ad esempio:
import sys
sys.path.insert(1, 'google-cloud-sdk/platform/google_appengine')
sys.path.insert(1, 'google-cloud-sdk/platform/google_appengine/lib/yaml/lib')
sys.path.insert(1, 'myapp/lib')
Importa il modulo unittest
di Python e i moduli di App Engine pertinenti
per i servizi in fase di test, in questo caso memcache
e ndb
, che utilizzano sia
il datastore sia memcache. Importa anche il modulo testbed
.
Quindi, crea un corso TestModel
. In questo esempio, una funzione controlla
se un'entità è archiviata in memcache. Se non viene trovata alcuna entità, controlla se
è presente un'entità nel datastore. Questo può spesso essere ridondante nella vita reale, dato che ndb
usa memcache dietro le tende, ma è comunque un modello accettabile per
un test.
Ora crea uno scenario di test. Indipendentemente dai servizi che stai testando, lo scenario di test
deve creare un'istanza Testbed
e attivarla. Lo scenario di test deve inoltre inizializzare gli stub di servizio pertinenti, in questo caso utilizzando init_datastore_v3_stub
e init_memcache_stub
. I metodi per inizializzare altri stub di servizio App Engine sono elencati in Introduzione alle utilità di test di Python.
Il metodo init_datastore_v3_stub()
senza argomento utilizza un datastore in memoria inizialmente vuoto. Se vuoi testare un'entità datastore esistente, includi il suo percorso come argomento a init_datastore_v3_stub()
.
Oltre a setUp()
, includi un metodo tearDown()
che disattivi il
testbed. In questo modo vengono ripristinati gli stub originali in modo che i test non interferiscano tra loro.
Poi implementa i test.
Ora puoi utilizzare TestModel
per scrivere test che utilizzano gli stub di servizio datastore o memcache invece di utilizzare i servizi reali.
Ad esempio, il metodo mostrato di seguito crea due entità: la prima entità utilizza il valore predefinito per l'attributo number
(42) e la seconda un valore non predefinito per number
(17). Il metodo crea quindi una query per
le entità TestModel
, ma solo per quelle con il valore predefinito number
.
Dopo aver recuperato tutte le entità corrispondenti, il metodo verifica che sia stata trovata una sola entità e che il valore predefinito dell'attributo number
di questa entità.
Come ulteriore esempio, il seguente metodo crea un'entità e la recupera
utilizzando la funzione GetEntityViaMemcache()
creata in precedenza. Il metodo quindi verifica che un'entità sia stata restituita e che il suo valore number
sia lo stesso dell'entità creata in precedenza.
Infine, richiama unittest.main()
.
Per eseguire i test, vedi Esecuzione dei test.
Scrittura dei test di Cloud Datastore
Se l'app utilizza Cloud Datastore, potrebbe essere opportuno scrivere
test che verificano il comportamento dell'applicazione a fronte della
coerenza finale.
db.testbed
mostra le opzioni che semplificano
l'operazione:
La classe PseudoRandomHRConsistencyPolicy
consente di controllare la probabilità che una scrittura venga applicata prima di ogni query globale (non predecessore). Impostando la probabilità su 0%, indichiamo allo stub del datastore di funzionare con la massima coerenza finale. La massima coerenza finale comporta il commit delle scritture, che però non verranno mai applicate, pertanto le query globali (non predecessori) non riusciranno a rilevare le modifiche. Questo non è ovviamente rappresentativo della quantità di coerenza finale che l'applicazione vedrà durante l'esecuzione in produzione ma, a scopo di test, è molto utile poter configurare il datastore locale in modo che si comporti ogni volta in questo modo. Se utilizzi una probabilità diversa da zero, PseudoRandomHRConsistencyPolicy
prende una sequenza deterministica di decisioni sulla coerenza, in modo che i risultati dei test siano coerenti:
Le API di test sono utili per verificare che l'applicazione si comporti correttamente a dispetto della coerenza finale, ma tieni presente che il modello locale con coerenza di lettura ad alta replica è un'approssimazione del modello di lettura ad alta coerenza di produzione, non una replica esatta. Nell'ambiente locale, l'esecuzione di un get()
di un Entity
che appartiene a un gruppo di entità con una scrittura non applicata renderà sempre visibili i risultati della scrittura non applicata alle query globali successive. In fase di produzione non è così.
Redazione dei test di posta
Puoi utilizzare lo stub del servizio di posta per testare il servizio mail. Analogamente ad altri servizi supportati da testbed, all'inizio si inizializza lo stub, si richiami il codice che utilizza l'API mail e infine si verifica se sono stati inviati i messaggi corretti.
Scrittura dei test delle coda di attività corso...
Puoi utilizzare lo stub della coda di attività per scrivere test che utilizzano il servizio taskqueue. Analogamente ad altri servizi supportati da testbed, all'inizio si inizializza lo stub, si richiami il codice che utilizza l'API Taskqueue e infine si verifica se le attività sono state aggiunte correttamente alla coda.
Impostazione del file di configurazione queue.yaml
Se vuoi eseguire test su codice che interagisce con una coda non predefinita, dovrai creare e specificare un file queue.yaml
da utilizzare per l'applicazione.
Di seguito è riportato un esempio di queue.yaml
:
Per ulteriori informazioni sulle opzioni della coda di attività disponibili, consulta la pagina sulla configurazione della coda delle attività.
La posizione di queue.yaml
viene specificata durante l'inizializzazione dello stub:
self.testbed.init_taskqueue_stub(root_path='.')
Nell'esempio, queue.yaml
si trova nella stessa directory dei test. Se si trovasse in un'altra cartella, quel percorso dovrà essere specificato in root_path
.
Applicazione di filtri alle attività
Lo stub della coda di attività get_filtered_tasks
consente di filtrare le attività in coda.
In questo modo è più semplice scrivere i test che devono verificare il codice che accoda
più attività.
Scrittura di test di attività differite
Se il codice dell'applicazione utilizza la libreria differita, puoi utilizzare lo stub coda di attività insieme a deferred
per verificare che le funzioni differite vengano accodate ed eseguite correttamente.
Modifica delle variabili di ambiente predefinite
I servizi App Engine spesso dipendono dalle variabili di ambiente. Il metodo activate()
della classe testbed.Testbed
utilizza valori predefiniti per questi valori, ma puoi impostare valori
personalizzati in base alle tue esigenze di test con il metodo setup_env
della classe testbed.Testbed
.
Ad esempio, supponiamo di avere un test in cui vengono archiviate diverse entità in un datastore, tutte collegate allo stesso ID applicazione. Ora vuoi eseguire di nuovo gli stessi test, ma utilizzando un ID applicazione diverso da quello collegato alle entità archiviate. Per farlo, passa il nuovo valore a
self.setup_env()
come app_id
.
Ad esempio:
Accesso simulato
Un altro uso frequente di setup_env
è simulare l'accesso di un utente,
con o senza privilegi amministrativi, per verificare che i gestori funzionino
correttamente in ogni caso.
Ora i tuoi metodi di test possono chiamare, ad esempio, self.loginUser('', '')
per
simulare nessun utente che ha eseguito l'accesso, self.loginUser('test@example.com', '123')
per
simulare l'accesso di un utente non amministratore e self.loginUser('test@example.com',
'123', is_admin=True)
per simulare l'accesso di un utente amministratore.
Configurazione di un framework di test
Le utilità di test dell'SDK non sono legate a un framework specifico. Puoi eseguire i test delle unità con qualsiasi testrunner di App Engine disponibile, ad esempio nose-gae o ferrisnose. Puoi anche scrivere un semplice testrunner personale o utilizzare quello mostrato di seguito.
I seguenti script utilizzano il modulo unittest di Python.
Puoi assegnare allo script il nome che preferisci. Quando lo esegui, fornisci il percorso di installazione dell'interfaccia a riga di Google Cloud CLI o dell'SDK di Google App Engine e il percorso dei moduli di test. Lo script rileverà tutti i test nel percorso fornito e stamperà i risultati nel flusso di errori standard. I file di test seguono la convenzione che prevede
di avere il prefisso test
al proprio nome.
Esecuzione dei test
È possibile eseguire questi test semplicemente eseguendo lo script runner.py
, descritto in dettaglio nella sezione Configurazione di un framework di test:
python runner.py <path-to-appengine-or-gcloud-SDK> .