I test delle unità ti consentono di verificare la qualità del codice dopo averlo scritto, ma puoi anche utilizzarli per migliorare il processo di sviluppo man mano che procedi. Anziché scrivere i test al termine dello sviluppo dell'applicazione, valuta la possibilità di scriverli man mano che procedi. In questo modo, puoi progettare unità di codice piccole, gestibili e riutilizzabili. Inoltre, ti consente di testare il codice in modo completo e rapido.
Quando esegui 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 puoi esercitare l'utilizzo di questi servizi da parte del tuo codice localmente, senza eseguire il deployment del codice in App Engine, utilizzando gli stub di servizio.
Uno stub del 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 datastore senza effettuare richieste al datastore reale. Qualsiasi entità archiviata durante un test unitario del datastore viene conservata in memoria, non nel datastore, e viene eliminata dopo l'esecuzione del test. Puoi eseguire test piccoli e veloci senza alcuna dipendenza dal datastore stesso.
Questo documento descrive come scrivere unit test per 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 chiamato
testbed
rende disponibili gli stub di servizio per i 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
) - 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 URL (utilizza
init_urlfetch_stub
) - Servizio utente (utilizza
init_user_stub
)
Per inizializzare tutti gli stub contemporaneamente, puoi utilizzare init_all_stubs
.
Scrivere test di Datastore e memcache
Questa sezione mostra un esempio di come scrivere codice che testa l'utilizzo dei servizi datastore e memcache.
Assicurati che il test runner disponga delle librerie appropriate nel percorso di caricamento di Python, incluse le librerie App Engine, yaml
(incluse nell'SDK App Engine), la radice dell'applicazione e qualsiasi altra modifica al percorso della libreria prevista dal codice dell'applicazione (ad esempio una directory ./lib
locale, se ne hai una). 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 App Engine pertinenti
ai servizi in fase di test, in questo caso memcache
e ndb
, che utilizzano sia
Datastore che Memcache. Importa anche il modulo
testbed
.
Poi crea un corso TestModel
. In questo esempio, una funzione controlla se
un'entità è archiviata in memcache. Se non viene trovata alcuna entità, viene cercata
un'entità nel datastore. Spesso questo può essere ridondante nella vita reale, poiché ndb
utilizza memcache dietro le quinte, ma è comunque un pattern accettabile per un
test.
Successivamente, crea uno scenario di test. Indipendentemente dai servizi che stai testando, lo scenario di test
deve creare un'istanza di Testbed
e attivarla. Il caso 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 di servizio App Engine sono elencati in Introduzione alle utilità di test
Python.
Il metodo init_datastore_v3_stub()
senza argomenti 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 disattiva 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 del datastore o di memcache anziché 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 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 altro esempio, il seguente metodo crea un'entità e la recupera
utilizzando la funzione GetEntityViaMemcache()
che abbiamo creato sopra. Il metodo
verifica quindi che sia stata restituita un'entità e che il suo valore number
sia lo stesso
dell'entità creata in precedenza.
Infine, invoca unittest.main()
.
Per eseguire i test, vedi Esecuzione dei test.
Scrittura di test di Cloud Datastore
Se la tua app utilizza Cloud Datastore, ti consigliamo di scrivere
test che verifichino il comportamento dell'applicazione in caso di
coerenza finale.
db.testbed
offre opzioni che semplificano
questa operazione:
La classe PseudoRandomHRConsistencyPolicy
consente di controllare la probabilità che una scrittura venga applicata prima di ogni query globale (non predecessore). Impostando la probabilità
sullo 0%, stiamo indicando allo stub del datastore di operare con la
massima quantità di coerenza finale. La coerenza finale massima significa che
le scritture verranno eseguite, ma non verranno mai applicate, quindi le query globali (non discendenti)
non vedranno mai le modifiche. Naturalmente, questo non è rappresentativo della quantità di coerenza finale che la tua applicazione vedrà durante l'esecuzione in produzione, ma a scopo di test è molto utile poter configurare il datastore locale in modo che si comporti in questo modo ogni volta. Se utilizzi una probabilità
diversa da zero, PseudoRandomHRConsistencyPolicy
crea 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 si comporti correttamente
in caso di coerenza finale, ma tieni presente che il modello di coerenza di lettura High
Replication locale è un'approssimazione del modello di coerenza di lettura High
Replication 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 produzione non è così.
Scrittura di test di posta
Puoi utilizzare lo stub del servizio di posta per testare il servizio mail. Analogamente ad altri servizi supportati da testbed, inizialmente inizializzi lo stub, poi richiami il codice che utilizza l'API Mail e infine verifichi se sono stati inviati i messaggi corretti.
Scrittura di test per le coda di attività
Puoi utilizzare lo stub taskqueue per scrivere test che utilizzano il servizio taskqueue. Analogamente ad altri servizi supportati da testbed, inizialmente inizializzi lo stub, poi richiami il codice che utilizza l'API Task Queue e infine verifichi se le attività sono state aggiunte correttamente alla coda.
Impostazione del file di configurazione queue.yaml
Se vuoi eseguire test sul codice che interagisce con una coda non predefinita, devi
creare e specificare un file queue.yaml
da utilizzare per la tua applicazione.
Di seguito è riportato un esempio di queue.yaml
:
Per ulteriori informazioni sulle opzioni queue.yaml disponibili, consulta la 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, il percorso dovrebbe essere specificato in root_path
.
Filtrare le attività
Lo stub taskqueue get_filtered_tasks
consente di filtrare le attività in coda.
In questo modo è più facile scrivere test che devono verificare il codice che mette in coda
più attività.
Scrittura di test per attività differite
Se il codice dell'applicazione utilizza la libreria differita, puoi utilizzare lo stub taskqueue insieme a deferred
per verificare che le funzioni differite siano accodate ed eseguite correttamente.
Modificare le variabili di ambiente predefinite
I servizi App Engine spesso dipendono dalle variabili di ambiente. Il metodo activate()
della classe testbed.Testbed
utilizza valori predefiniti, 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 che memorizza diverse entità in
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 in
self.setup_env()
come app_id
.
Ad esempio:
Simulazione dell'accesso
Un altro utilizzo frequente di setup_env
è la simulazione dell'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 chiamare, ad esempio, self.loginUser('', '')
per
simulare l'assenza di un utente connesso, 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.
Configurare un framework di test
Le utilità di test dell'SDK non sono legate a un framework specifico. Puoi eseguire i test unitari con qualsiasi test runner App Engine disponibile, ad esempio nose- gae o ferrisnose. Puoi anche scrivere un semplice testrunner o utilizzare quello mostrato di seguito.
I seguenti script utilizzano il modulo unittest di Python.
Puoi assegnare al copione il nome che preferisci. Quando lo esegui, fornisci il percorso
dell'installazione di Google Cloud CLI o Google App Engine SDK 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 del nome.
Esecuzione dei test
Puoi eseguire questi test semplicemente eseguendo lo script runner.py
, che è
descritto in dettaglio nella sezione Configurazione di un framework di test:
python runner.py <path-to-appengine-or-gcloud-SDK> .