Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Test unitari
Godot Engine permette di scrivere test unitari direttamente in C++. Il motore integra il framework di test unitari doctest, che consente di scrivere suite e casi di test accanto al codice di produzione. Tuttavia, poiché i test in Godot passano attraverso un punto di ingresso main diverso, risiedono in una cartella tests/ dedicata, situata alla radice del codice sorgente del motore.
Platform and target support
I test unitari in C++ si possono eseguire sui sistemi operativi Linux, macOS e Windows.
I test si possono eseguire solo con gli strumenti (tools) dell'editor abilitati, il che significa che al momento i modelli di esportazione non si possono testare.
Eseguire i test
Prima che i test possano essere effettivamente eseguiti, il motore deve essere compilato con l'opzione di compilazione tests abilitata (e qualsiasi altra opzione di compilazione utilizzata solitamente), poiché i test normalmente non vengono compilati come parte del motore:
scons tests=yes
Una volta completata la compilazione, eseguire i test con l'opzione della riga di comando --test:
./bin/<godot_binary> --test
L'esecuzione del test può essere configurata con le varie opzioni della riga di comando specifiche di doctest. Per ottenere l'elenco completo delle opzioni supportate, eseguire il comando --test con l'opzione --help:
./bin/<godot_binary> --test --help
Tutte le altre opzioni e argomenti dopo il comando --test sono trattati come argomenti per doctest.
Nota
I test vengono compilati automaticamente se si utilizza l'opzione SCons dev_mode=yes. dev_mode=yes è consigliato se si prevede di contribuire allo sviluppo del motore, poiché tratterà automaticamente gli avvisi di compilazione come errori. Il sistema di integrazione continua non funzionerà se vengono rilevati avvisi di compilazione, quindi è consigliabile correggere tutti gli avvisi prima di aprire una richiesta di pull.
Filtrare i test
Normalmente, tutti i test vengono eseguiti se non si forniscono argomenti aggiuntivi dopo il comando --test. Tuttavia, se si stanno scrivendo nuovi test o si desidera visualizzare l'output delle asserzioni riuscite provenienti da tali test a scopo di debug, è possibile eseguire i test di interesse con le varie opzioni di filtro fornite da doctest.
La sintassi jolly * è supportata per corrispondere qualsiasi numero di caratteri nelle suite di test, nei casi di test e nei nomi dei file sorgente:
Opzioni di filtraggio |
Abbreviazione |
Esempi |
|
|
|
|
|
|
|
|
|
Ad esempio, per eseguire solo i test unitari String, eseguire:
./bin/<godot_binary> --test --test-case="*[String]*"
L'output delle asserzioni riuscite si può abilitare con l'opzione --success (-s), e si può combinare con qualsiasi altre opzioni di filtro sopra indicate, ad esempio:
./bin/<godot_binary> --test --source-file="*test_color*" --success
È possibile saltare test specifici con le opzioni -exclude corrispondenti. Al momento, alcuni test includono stress test di casualità la cui esecuzione richiede un po' di tempo. Per saltare questi tipi di test, eseguire il seguente comando:
./bin/<godot_binary> --test --test-case-exclude="*[Stress]*"
Scrivere i test
Le suite di test rappresentano file di implementazione C++ che devono includere la macro TEST_FORCE_LINK(). La maggior parte delle suite di test si trova direttamente nella cartella tests/.
Tutti i file di test hanno il prefisso test_, una convenzione di denominazione su cui si basa il sistema di compilazione Godot per rilevare i test in tutto il motore.
Ecco una suite di test minima e funzionante con un singolo caso di test scritto:
#include "tests/test_macros.h"
TEST_FORCE_LINK(test_string)
namespace TestString {
TEST_CASE("[String] Hello World!") {
String hello = "Hello World!";
CHECK(hello == "Hello World!");
}
} // namespace TestString
Nota
È possibile generare rapidamente nuovi test tramite lo script create_test.py presente nella cartella tests/. Questo script crea automaticamente un nuovo file di test con il codice boilerplate richiesto nel posto appropriato. Per visualizzare le istruzioni d'uso, eseguire lo script con il flag -h.
L'intestazione tests/test_macros.h incapsula tutto il necessario per scrivere test unitari in C++ in Godot. Include macro di asserzione e log dei doctest come CHECK come visto in precedenza, e ovviamente le definizioni per scrivere i casi di test stessi.
Vedi anche
tests/test_macros.h codice sorgente riguardo ogni macro e alias attualmente implementato.
I casi di test si creano utilizzando la macro TEST_CASE, simile a una funzione. Ogni caso di test deve avere una breve descrizione tra parentesi, includendo facoltativamente tag personalizzati che consentono di filtrare i test durante l'esecuzione, come [String], [Stress] ecc.
I casi di test vengono scritti in uno spazio dei nomi dedicato. Questo non è obbligatorio, ma consente di evitare conflitti di nomi quando altre funzioni ausiliari statiche vengono scritte per gestire le procedure di test ripetute, come popolare i dati di test comuni per ogni test o scrivere test parametrici.
Godot supporta la scrittura di test per modulo C++. Per istruzioni su come scrivere test per modulo, fare riferimento a Scrivere test unitari personalizzati.
Sotto-casi
In situazioni in cui c'è una configurazione comune per diversi casi di test con solo lievi variazioni, i sotto-casi possono essere molto utili. Ecco un esempio:
TEST_CASE("[SceneTree][Node] Testing node operations with a very simple scene tree") {
// ... common setup (e.g. creating a scene tree with a few nodes)
SUBCASE("Move node to specific index") {
// ... setup and checks for moving a node
}
SUBCASE("Remove node at specific index") {
// ... setup and checks for removing a node
}
}
Ogni SUBCASE assicura che TEST_CASE venga eseguito dall'inizio. I sotto-casi si possono annidare a una profondità arbitraria, ma si consiglia di limitare l'annidamento a non più di un livello di profondità.
Asserzioni
Elenco di tutte le asserzioni comunemente utilizzate nei test di Godot, ordinate in base alla severità.
Asserzione |
Descrizione |
|
Verifica se la condizione è vera. Fallisce immediatamente l'intero test se la condizione non è vera. |
|
Verifica se la condizione non è vera. Fallisce immediatamente l'intero test se la condizione è vera. |
|
Verifica se la condizione è vera. Contrassegna il giro di test come fallito, ma permette di eseguire altre asserzioni. |
|
Verifica se la condizione non è vera. Contrassegna il giro di test come fallito, ma permette di eseguire altre asserzioni. |
|
Verifica se la condizione è vera. Non fallisce il test in nessuna circostanza, ma registra un avviso se qualcosa non è vero. |
|
Verifica se la condizione non è vera. Non fallisce il test in nessuna circostanza, ma registra un avviso se qualcosa è vero. |
Tutte le suddette asserzioni hanno macro *_MESSAGE corrispondenti, le quali consentono di stampare un messaggio facoltativo con una spiegazione di cosa dovrebbe accadere.
È preferibile utilizzare CHECK per le asserzioni auto-esplicative e CHECK_MESSAGE per quelle più complesse, se si ritiene che meritino una spiegazione migliore.
Vedi anche
Logging
Il risultato del test è gestito da doctest stesso e non dipende in alcun modo dalla funzionalità di stampa o di registrazione di Godot, quindi si consiglia di utilizzare le macro dedicate, che consentono di registrare il risultato del test in un formato scritto da doctest.
Macro |
Descrizione |
|
Stampa un messaggio. |
|
Contrassegna il test come fallito, ma continua l'esecuzione. Può essere racchiuso in istruzioni condizionali per verifiche complesse. |
|
Fallisce immediatamente il test. Può essere racchiuso in istruzioni condizionali per verifiche complesse. |
È possibile scegliere diversi segnalatori in fase di esecuzione. Ad esempio, ecco come l'output può essere reindirizzato a un file XML:
./bin/<godot_binary> --test --source-file="*test_validate*" --success --reporters=xml --out=doctest.txt
Vedi anche
Testare percorsi di errore
A volte, non è sempre possibile testare un risultato previsto. Considerando la filosofia di sviluppo di Godot, secondo cui il motore non dovrebbe bloccarsi e dovrebbe ripristinarsi correttamente ogni volta che si verifica un errore non fatale, è importante verificare che tali percorsi di errore siano effettivamente sicuri da eseguire senza causare un crash del motore.
Un comportamento inaspettato può essere testato come qualsiasi altra cosa. L'unico problema è che la stampa degli errori inquinerebbe inutilmente l'output dei test con errori provenienti dal motore stesso (anche se il risultato finale fosse un successo).
Per alleviare questo problema, utilizzare le macro ERR_PRINT_OFF e ERR_PRINT_ON direttamente dentro i casi di test per disattivare temporaneamente l'output di errore proveniente dal motore, ad esempio:
TEST_CASE("[Color] Constructor methods") {
ERR_PRINT_OFF;
Color html_invalid = Color::html("invalid");
ERR_PRINT_ON; // Don't forget to re-enable!
CHECK_MESSAGE(html_invalid.is_equal_approx(Color()),
"Invalid HTML notation should result in a Color with the default values.");
}
Testare i segnali
Per testare i segnali è possibile utilizzare le seguenti macro:
Macro |
Descrizione |
|---|---|
|
Comincia a osservare il segnale specificato sull'oggetto specificato. |
|
Finisce a osservare il segnale specificato sull'oggetto specificato. |
|
Verifica gli argomenti di tutti i segnali attivati. Il vettore esterno contiene ogni segnale attivato, mentre il vettore interno contiene l'elenco degli argomenti per quel segnale. L'ordine dei segnali è importante. |
|
Controlla se il segnale specificato non è stato attivato. |
|
Scarta tutte le registrazioni del segnale specificato. |
Di seguito è riportato un esempio che dimostra l'uso di queste macro:
//...
SUBCASE("[Timer] Timer process timeout signal must be emitted") {
SIGNAL_WATCH(test_timer, SNAME("timeout"));
test_timer->start(0.1);
SceneTree::get_singleton()->process(0.2);
Array signal_args;
signal_args.push_back(Array());
SIGNAL_CHECK(SNAME("timeout"), signal_args);
SIGNAL_UNWATCH(test_timer, SNAME("timeout"));
}
//...
Strumenti di test
Gli strumenti di test sono metodi avanzati che consentono di eseguire procedure arbitrarie per facilitare il processo di test manuale e il debugging dei componenti interni del motore.
Questi strumenti si possono eseguire specificandone il nome dopo l'opzione --test della riga di comando. Ad esempio, il modulo GDScript implementa e registra diversi strumenti per facilitare il debugging del tokenizzatore, del parser e del compilatore:
./bin/<godot_binary> --test gdscript-tokenizer test.gd
./bin/<godot_binary> --test gdscript-parser test.gd
./bin/<godot_binary> --test gdscript-compiler test.gd
Se uno di questi strumenti viene rilevato, i test unitari rimanenti vengono saltati.
Gli strumenti di test si possono registrare ovunque nel motore, poiché il meccanismo di registrazione è molto simile a quello fornito da doctest durante la registrazione dei casi di test tramite la tecnica di inizializzazione dinamica, ma solitamente si possono registrare nelle corrispondenti sorgenti register_types.cpp (per modulo o core).
Ecco un esempio di come GDScript registra gli strumenti di test in modules/gdscript/register_types.cpp:
#ifdef TESTS_ENABLED
void test_tokenizer() {
TestGDScript::test(TestGDScript::TestType::TEST_TOKENIZER);
}
void test_parser() {
TestGDScript::test(TestGDScript::TestType::TEST_PARSER);
}
void test_compiler() {
TestGDScript::test(TestGDScript::TestType::TEST_COMPILER);
}
REGISTER_TEST_COMMAND("gdscript-tokenizer", &test_tokenizer);
REGISTER_TEST_COMMAND("gdscript-parser", &test_parser);
REGISTER_TEST_COMMAND("gdscript-compiler", &test_compiler);
#endif
L'analisi personalizzata della riga di comando può essere eseguita da uno strumento di test stesso con l'ausilio del metodo get_cmdline_args di OS.
Test di integrazione per GDScript
Godot utilizza doctest per prevenire regressioni in GDScript durante lo sviluppo. Esistono diversi tipi di script di test che si possono scrivere:
test per gli errori previsti;
test per gli avvertimenti;
test per le funzionalità.
Pertanto, il processo di scrittura dei test di integrazione per GDScript è il seguente:
Scegliere il tipo di script di test che si desidera scrivere e creare un nuovo file GDScript nella cartella
modules/gdscript/tests/scriptsall'interno della sottocartella corrispondente.Scrivere il codice GDScript. Lo script di test deve avere una funzione chiamata
test()che non accetta argomenti. Tale funzione verrà chiamata dal test runner. Il test non deve avere alcuna dipendenza, a meno che ciò non faccia parte del test stesso. Le classi globali (quelle che usanoclass_name) vengono registrate prima dell'avvio del test runner, quindi queste dovrebbero funzionare se necessario.Ecco uno script di test di esempio:
func test(): if true # Missing colon here. print("true")
Cambiare la cartella alla radice del repository sorgente di Godot.
cd godot
Generare i file
*.outper aggiornare i risultati previsti dall'output:bin/<godot_binary> --gdscript-generate-tests modules/gdscript/tests/scripts
È possibile aggiungere l'opzione --print-filenames per visualizzare i nomi dei file durante la generazione dei relativi output di test. Se si sta lavorando a una nuova funzionalità che causa crash improvvisi, è possibile utilizzare questa opzione per individuare rapidamente il file di test che causa il crash e effettuare il debug da lì.
Esegui i test di GDScript con:
./bin/<godot_binary> --test --test-suite="*GDScript*"
Accetta anche l'opzione --print-filenames (vedere in precedenza).
Se non vengono stampati errori e tutto va bene, ecco fatto!
Avvertimento
Assicurarsi che l'output contenga effettivamente i valori previsti prima di inviare una richiesta di pull. Se --gdscript-generate-tests produce file *.out che non riguardano i nuovi test aggiunti, si dovrebbero ripristinare tali file e inviare i file *.out solo per i nuovi test.
Nota
Il test runner di GDScript è pensato per testare l'implementazione di GDScript, non per testare gli script utente né per testare il motore tramite script. Consigliamo di scrivere nuovi test per i problemi relativi a GDScript già risolti su GitHub, oppure di scrivere test per le funzionalità attualmente funzionanti.
Nota
Se il caso di test richiede che nessuna funzione test() sia presente dentro il file di script, è possibile disabilitare la sezione runtime del test rinominando il file di script in modo che corrisponda al pattern *.notest.gd. Ad esempio, "test_empty_file.notest.gd".