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. Invece di scrivere i test dopo aver completato lo sviluppo dell'applicazione, ti consigliamo di scriverli man mano che procedi. In questo modo, puoi progettare unità di codice piccole, gestibili e riutilizzabili. Inoltre, ti consente di testare il tuo codice in modo rapido e completo in modo più semplice.
Quando esegui test delle unità locali, esegui test che rimangono all'interno del tuo ambiente di sviluppo senza coinvolgere i componenti remoti. App Engine fornisce utilità di test che utilizzano implementazioni locali di datastore e altri servizi App Engine. Ciò significa che puoi esercitare il tuo codice nell'utilizzo di questi servizi in locale, senza eseguire il deployment del codice in App Engine, utilizzando 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 ti consente di testare il codice del datastore senza effettuare richieste al datastore reale. Qualsiasi entità archiviata durante un test delle unità del datastore viene conservata in memoria, non nel datastore, e viene eliminata dopo l'esecuzione del test. Puoi eseguire piccoli test veloci senza alcuna dipendenza dal datastore stesso.
Questo documento descrive come scrivere test delle unità su diversi servizi App Engine locali, quindi fornisce alcune informazioni sulla configurazione di un framework di test.
Introduzione alle utilità di test Python 2
Un modulo Python di App Engine denominato testbed
rende disponibili gli stub di servizio per il test delle unità.
Le stub di servizio sono disponibili per i seguenti servizi:
- Identità app
init_app_identity_stub
- Archivio BLOB (utilizza
init_blobstore_stub
) - Funzionalità (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 dell'URL (utilizza
init_urlfetch_stub
) - Servizio utente (utilizza
init_user_stub
)
Per inizializzare tutte le stub contemporaneamente, puoi utilizzare init_all_stubs
.
Scrittura dei test Datastore e memcache
Questa sezione mostra un esempio di come scrivere codice che verifichi l'utilizzo dei servizi datastore e memcache.
Assicurati che l'esecutore del test disponga delle librerie appropriate nel percorso di caricamento Python, tra cui le librerie di App Engine, yaml
(incluse nell'SDK App Engine), la directory principale dell'applicazione e qualsiasi altra modifica al percorso della libreria prevista 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 Python unittest
e i moduli di App Engine pertinenti per i servizi testati, in questo caso memcache
e ndb
, che utilizza 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à, cerca un'entità nel datastore. Questo può essere spesso ridondante nella realtà, dato che ndb
utilizza memcache automaticamente dietro le tende, ma è comunque un pattern accettabile per
un test.
Quindi, 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 anche inizializzare gli stub di servizio pertinenti, in questo caso utilizzando init_datastore_v3_stub
e init_memcache_stub
. I metodi per inizializzare altri stub del servizio App Engine sono elencati in Introduzione alle utilità di test 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 relativo percorso come argomento di 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.
Quindi, implementa i test.
Ora puoi usare TestModel
per scrivere test che utilizzano stub del servizio datastore o memcache invece di usare i servizi reali.
Ad esempio, il metodo mostrato di seguito crea due entità: la prima utilizza
il valore predefinito per l'attributo number
(42) e la seconda utilizza 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 di number
.
Dopo aver recuperato tutte le entità corrispondenti, il metodo verifica che sia stata trovata esattamente un'entità e che il valore dell'attributo number
di questa entità sia il valore predefinito.
Come ulteriore esempio, il metodo seguente crea un'entità e la recupera utilizzando la funzione GetEntityViaMemcache()
creata in precedenza. Il metodo verifica quindi che un'entità è stata restituita e che il valore number
sia lo stesso dell'entità creata in precedenza.
Infine, richiama unittest.main()
.
Per eseguire i test, consulta Esecuzione di test.
Scrittura di test di Cloud Datastore
Se la tua app utilizza Cloud Datastore, potresti voler scrivere test che verificano il comportamento dell'applicazione nonostante l'eventuale coerenza.
db.testbed
mostra opzioni che
semplificano:
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 significa che le scritture eseguiranno il commit, ma non verranno sempre applicate, quindi le query globali (non predecessori) non noteranno costantemente le modifiche. Ovviamente questo non è rappresentativo della quantità di coerenza finale che l'applicazione riceverà durante l'esecuzione in produzione, ma ai fini di test è molto utile configurare il datastore locale in modo che si comporti ogni volta in questo modo. Se utilizzi una probabilità diversa da zero, PseudoRandomHRConsistencyPolicy
effettua una sequenza deterministica di decisioni di coerenza in modo che i risultati del test siano coerenti:
Le API di test sono utili per verificare che l'applicazione funzioni correttamente
nonostante la coerenza finale, ma tieni presente che il modello locale di coerenza di lettura ad alta replica è un'approssimazione del modello di produzione a coerenza di lettura ad alta
Replica, non di 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 per le successive query globali. In produzione, non è così.
Scrittura di test della posta
Puoi utilizzare la bozza del servizio di posta per provare il servizio mail. Analogamente ad altri servizi supportati da testbed, inizialmente si inizializza lo stub, quindi si richiama 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 usano il servizio taskqueue. Come per gli altri servizi supportati da testbed, inizialmente devi inizializzare lo stub, quindi richiamare il codice che utilizza l'API Taskqueue e, infine, verificare 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 queue.yaml
:
Per saperne di più sulle opzioni disponibiliQueue.yaml, consulta la configurazione delle code di 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, il percorso dovrà essere specificato in root_path
.
Filtrare le attività
L'elemento get_filtered_tasks
dello stub della coda di attività consente di filtrare le attività in coda.
In questo modo è più facile scrivere test che devono verificare il codice che accoda più attività.
Scrittura di test delle attività differite
Se il codice dell'applicazione utilizza la libreria differita, puoi utilizzare lo stub della coda di attività insieme a deferred
per verificare che le funzioni differite siano in coda ed eseguite correttamente.
Modifica delle variabili di ambiente predefinite
I servizi App Engine dipendono spesso da variabili di ambiente. Il metodo activate()
della classe testbed.Testbed
utilizza i valori predefiniti, ma puoi impostare valori
personalizzati in base alle tue esigenze di test con il metodo setup_env
di classe testbed.Testbed
.
Ad esempio, supponiamo di avere un test che archivia diverse entità nel 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. A questo scopo, passa il nuovo valore in
self.setup_env()
come app_id
.
Ad esempio:
Simulazione dell'accesso
Un altro uso frequente di setup_env
è simulare l'accesso di un utente, con o senza privilegi amministrativi, per verificare se i gestori funzionano correttamente in ogni caso.
Ora i tuoi metodi di test possono richiamare, ad esempio, self.loginUser('', '')
per simulare l'accesso di nessun utente, self.loginUser('test@example.com', '123')
per simulare l'accesso di un utente non amministratore, 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 test runner semplice oppure utilizzare quello mostrato di seguito.
Gli script seguenti utilizzano il modulo unittest di Python.
Puoi assegnare allo script il nome che preferisci. Quando lo esegui, fornisci il percorso dell'installazione 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 di avere test
come prefisso al nome.
Esecuzione dei test
Puoi eseguire questi test semplicemente eseguendo lo script runner.py
, descritto dettagliatamente nella sezione Configurazione di un framework di test:
python runner.py <path-to-appengine-or-gcloud-SDK> .