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 fornisce alcune informazioni sulla configurazione di un framework di test, quindi descrive come scrivere unit test per diversi servizi locali di App Engine.
Configurare un framework di test
Anche se le utilità di test dell'SDK non sono associate a nessun framework specifico, questa guida utilizza JUnit per gli esempi, in modo da avere qualcosa di concreto e completo da cui partire. Prima di iniziare a scrivere i test, devi aggiungere il file JAR di JUnit 4 appropriato al classpath di test. Una volta fatto, puoi scrivere un test JUnit molto semplice.
Se esegui Eclipse, seleziona il file di origine del test da eseguire. Seleziona il menu Esegui > Esegui come > Test JUnit. I risultati del test vengono visualizzati nella finestra della console.
Introduzione delle utilità di test Java 8
MyFirstTest
mostra la configurazione di test più semplice possibile e, per i test che
non hanno alcuna dipendenza dalle API App Engine o dalle implementazioni di servizi locali, potresti
non aver bisogno di altro. Tuttavia, se i test o il codice in fase di test hanno
queste dipendenze, aggiungi i seguenti file JAR al classpath di test:
${SDK_ROOT}/lib/impl/appengine-api.jar
${SDK_ROOT}/lib/impl/appengine-api-stubs.jar
${SDK_ROOT}/lib/appengine-tools-api.jar
Questi file JAR rendono disponibili per i test le API di runtime e le implementazioni locali di queste API.
I servizi App Engine si aspettano una serie di cose dal loro ambiente di esecuzione
e la configurazione di queste cose comporta una discreta quantità di codice boilerplate. Anziché
configurarlo manualmente, puoi utilizzare le utilità nel
pacchetto com.google.appengine.tools.development.testing
. Per utilizzare questo pacchetto,
aggiungi il seguente file JAR al classpath di test:
${SDK_ROOT}/lib/testing/appengine-testing.jar
Prenditi un minuto per sfogliare la
javadoc per il
pacchetto com.google.appengine.tools.development.testing
. La classe più importante
di questo pacchetto è
LocalServiceTestHelper,
che gestisce tutta la configurazione dell'ambiente necessaria e fornisce un punto di configurazione di primo livello per tutti i servizi locali a cui potresti voler accedere nei test.
Per scrivere un test che accede a un servizio locale specifico:
- Crea un'istanza di
LocalServiceTestHelper
con un'implementazioneLocalServiceTestConfig
per quel servizio locale specifico. - Chiama
setUp()
nella tua istanzaLocalServiceTestHelper
prima di ogni test etearDown()
dopo ogni test.
Scrivere test di Datastore e memcache
Il seguente esempio testa l'utilizzo del servizio datastore.
In questo esempio, LocalServiceTestHelper
configura e smonta le parti dell'ambiente di esecuzione comuni a tutti i servizi locali, mentre LocalDatastoreServiceTestConfig
configura e smonta le parti dell'ambiente di esecuzione specifiche del servizio datastore locale. Se
leggi la javadoc,
scoprirai che ciò comporta la configurazione del servizio datastore locale per conservare
tutti i dati in memoria (anziché scaricarli su disco a intervalli regolari) e
cancellare tutti i dati in memoria alla fine di ogni test. Questo è solo il comportamento predefinito per un test del datastore e, se non è quello che vuoi, puoi modificarlo.
Modifica dell'esempio per accedere a memcache anziché a Datastore
Per creare un test che acceda al servizio memcache locale, puoi utilizzare il codice mostrato sopra, con alcune piccole modifiche.
Anziché importare le classi correlate a Datastore, importa quelle correlate a
memcache. Devi ancora importare LocalServiceTestHelper
.
Modifica il nome della classe che stai creando e l'istanza di
LocalServiceTestHelper
in modo che siano specifiche per memcache.
Infine, modifica il modo in cui esegui il test in modo che sia pertinente a memcache.
Come nell'esempio del datastore, LocalServiceTestHelper
e LocalServiceTestConfig
specifico del servizio (in questo caso LocalMemcacheServiceTestConfig
) gestiscono l'ambiente di esecuzione.
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. LocalDatastoreServiceTestConfig
mostra le opzioni che semplificano
questa operazione:
Se imposti la percentuale di job non applicati su 100, indichi al datastore locale di operare con la massima coerenza finale. La coerenza finale massima indica che le scritture verranno eseguite, ma non verranno mai applicate, pertanto le query globali (non discendenti) non riusciranno a visualizzare 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 l'archivio dati locale in modo che si comporti in questo modo ogni volta.
Se vuoi un controllo più granulare sulle transazioni che non vengono applicate, puoi registrare il tuo HighRepJobPolicy
:
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 per le coda di attività
I test che utilizzano la coda di attività locale sono un po' più complessi perché, a differenza di
datastore e memcache, l'APIcoda di attivitàe non espone una funzionalità per
esaminare lo stato del servizio. Dobbiamo accedere alla coda di attività locale
per verificare che un'attività sia stata pianificata con i parametri previsti. Per
farlo, abbiamo bisogno di com.google.appengine.api.taskqueue.dev.LocalTaskQueue
.
Nota come chiediamo a LocalTaskqueueTestConfig
un handle per l'istanza del servizio locale e poi esaminiamo il servizio locale stesso per assicurarci che l'attività sia stata pianificata come previsto. Tutte le implementazioni di LocalServiceTestConfig
espongono un metodo simile. Potresti non averne sempre bisogno, ma prima o poi
sarai felice di averlo.
Impostazione del file di configurazione queue.xml
Le librerie di test della coda di attività consentono di specificare un numero qualsiasi di configurazioni queue.xml
in base a LocalServiceTestHelper tramite
il metodo LocalTaskQueueTestConfig.setQueueXmlPath
. Al momento, le impostazioni del limite di frequenza di qualsiasi coda vengono ignorate dal server di sviluppo locale.
Non è possibile eseguire attività simultanee contemporaneamente in locale.
Ad esempio, un progetto potrebbe dover eseguire test sul file
queue.xml
che verrà caricato e utilizzato dall'applicazione
App Engine. Supponendo che il file queue.xml
si trovi nella posizione standard, il codice campione riportato sopra potrebbe essere modificato nel seguente modo per concedere all'utente di test l'accesso alle code specificate nel file src/main/webapp/WEB-INF/queue.xml
:
Modifica il percorso del file queue.xml
in modo che corrisponda alla struttura dei file del progetto.
Utilizza il metodo QueueFactory.getQueue
per accedere alle code per nome:
Scrittura di test per attività differite
Se il codice dell'applicazione utilizza Deferred Tasks, le utilità di test Java semplificano la scrittura di un test di integrazione che verifica i risultati di queste attività.
Come nel primo esempio di coda delle attività locali, utilizziamo un
LocalTaskqueueTestConfig
, ma questa volta lo inizializziamo con alcuni
argomenti aggiuntivi che ci consentono di verificare facilmente non solo che l'attività
sia stata pianificata, ma anche che sia stata eseguita: chiamiamo
setDisableAutoTaskExecution(false)
per indicare alla coda delle attività locali di
eseguire automaticamente le attività. Chiamiamo
setCallbackClass(LocalTaskQueueTestConfig.DeferredTaskCallback.class)
per dire
alla coda di attività locale di utilizzare un callback che sappia come eseguire le attività differite. Infine, chiamiamo setTaskExecutionLatch(latch)
per indicare alla coda di attività locale di decrementare il latch dopo l'esecuzione di ogni attività. Questa configurazione
ci consente di scrivere un test in cui mettiamo in coda un'attività differita, aspettiamo che
venga eseguita e poi verifichiamo che si sia comportata come previsto.
Scrivere test delle funzionalità dei servizi locali
Il test delle funzionalità prevede la modifica dello stato di alcuni servizi, ad esempio datastore, blobstore, memcache e così via, e l'esecuzione dell'applicazione rispetto a quel servizio per determinare se l'applicazione risponde come previsto in diverse condizioni. Lo stato della funzionalità può essere modificato utilizzando la classe LocalCapabilitiesServiceTestConfig.
Il seguente snippet di codice modifica lo stato della funzionalità del servizio datastore in disabilitato, quindi esegue un test sul servizio datastore. Puoi sostituire altri servizi a datastore in base alle esigenze.
Il test di esempio crea prima un oggetto Capability
inizializzato in Datastore,
poi crea un oggetto CapabilityStatus
impostato su DISABLED. LocalCapabilitiesServiceTestConfig
viene creato con la funzionalità e lo stato
impostati utilizzando gli oggetti Capability
e CapabilityStatus
appena creati.
LocalServiceHelper
viene quindi creato utilizzando l'oggetto
LocalCapabilitiesServiceTestConfig
. Ora che il test è stato configurato,
viene creato DatastoreService
e gli viene inviata una query per determinare se
il test genera i risultati previsti, in questo caso un
CapabilityDisabledException
.
Scrivere test per altri servizi
Sono disponibili utilità di test per Blobstore e altri servizi App Engine. Per
un elenco di tutti i servizi che hanno implementazioni locali per i test, consulta la
documentazione di LocalServiceTestConfig
.
Scrivere test con aspettative di autenticazione
Questo esempio mostra come scrivere test che verificano la logica che utilizza UserService per determinare se un utente ha eseguito l'accesso o dispone dei privilegi di amministratore. Tieni presente che qualsiasi utente con il ruolo di base Visualizzatore, Editor o Proprietario oppure con il ruolo predefinito Amministratore app App Engine dispone di privilegi amministrativi.
In questo esempio, stiamo configurando LocalServiceTestHelper
con
LocalUserServiceTestConfig
in modo da poter utilizzare UserService
nel nostro test, ma
stiamo anche configurando alcuni dati di ambiente correlati all'autenticazione su
LocalServiceTestHelper
stesso.
In questo esempio, stiamo configurando LocalServiceTestHelper
con
LocalUserServiceTestConfig
in modo da poter utilizzare OAuthService
.