Dopo aver modificato o aggiunto codice, devi eseguire i test delle unità esistenti e valutare la possibilità di scriverne altri. Tutti i test vengono eseguiti sulle versioni non compresse del codice.
Esistono due insiemi di test delle unità: test JS e test del generatore di blocchi.
Test JS
I test JS confermano il funzionamento delle funzioni JavaScript interne nell'interfaccia principale. Utilizziamo Mocha per eseguire i test delle unità, da Sinon a stub le dipendenze Chai per fare affermazioni sul codice.
Esecuzione dei test
Sia negli esempi a blocchi che in quelli a blocchi, npm run test
eseguirà i test delle unità. Nella
a blocchi, verranno eseguiti anche altri test come lint e la compilazione. Puoi anche aprire tests/mocha/index.html
in un browser per eseguire in modo interattivo tutti i test mocha.
Test di scrittura
Utilizziamo l'interfaccia TDD di Mocha per eseguire i test. I test sono organizzati in suite,
che possono contenere sia sottosuite aggiuntive e/o test. In genere, ogni
componente di Blockly (ad esempio toolbox
o workspace
) ha il proprio file di test
che contiene una o più suite. Ogni suite può avere un metodo setup
e teardown
che verrà chiamato rispettivamente prima e dopo ogni test della
suite.
Componenti di supporto per i test
Abbiamo varie funzioni helper specifiche di Blockly che possono essere utili quando e scrivere test. Puoi trovarli in core e in blockly-samples.
Le funzioni di supporto includono sharedTestSetup
e sharedTestTeardown
, che devono essere obbligatoriamente chiamate prima e dopo i test (vedi la sezione Requisiti).
sharedTestSetup
:
- Configura timer falsi (in alcuni test dovrai usare
this.clock.runAll
). - Simula Blockly.Events.fire per attivarsi immediatamente (configurabile).
- Configura la pulizia automatica dei tipi di blocco definiti tramite
defineBlocksWithJsonArray
. - Dichiara alcune proprietà nel contesto di
this
che dovrebbero essere accessibile:this.clock
(ma non deve essere ripristinato, altrimenti causerà problemi insharedTestTeardown
)this.eventsFireStub
this.sharedCleanup
(da utilizzare conaddMessageToCleanup
eaddBlockTypeToCleanup
) (NOTA: non è necessario utilizzareaddBlockTypeToCleanup
se hai definito il blocco utilizzandodefineBlocksWithJsonArray
)
La funzione ha un parametro options
facoltativo per configurare la configurazione. Al momento,
viene usato solo per determinare se lo stubing di Blockly.Events.fire
immediatamente (sarà stub per impostazione predefinita).
sharedTestTeardown
:
- Gestisce l'area di lavoro
this.workspace
(a seconda di dove è stata definita, consulta la sezione Requisiti di test per ulteriori informazioni). - Ripristina tutti gli stub.
- Ripulisce tutti i tipi di blocchi aggiunti tramite
defineBlocksWithJsonArray
eaddBlockTypeToCleanup
. - Consente di eliminare tutti i messaggi aggiunti tramite
addMessageToCleanup
.
Requisiti per i test
- Ogni test deve chiamare
sharedTestSetup.call(this);
come prima riga nel setup della suite più esterna esharedTestTeardown.call(this);
come ultima riga nel teardown della suite più esterna per un file. - Se hai bisogno di un'area di lavoro con una serie di strumenti generici, puoi usare uno dei
strumenti preimpostati
nel test
index.html
. Di seguito è riportato un esempio. - Devi smaltire correttamente
this.workspace
. Nella maggior parte dei test, definiraithis.workspace
nella suite più esterna e la utilizzerai per tutti i test successivi, ma in alcuni casi potresti definirla o ridefinirla in una suite interna (ad esempio, uno dei tuoi test richiede uno spazio di lavoro con opzioni diverse da quelle che hai configurato inizialmente). Deve essere smaltito al termine del test.- Se definisci
this.workspace
nella suite più esterna e non ridefini mai non devi fare altro. Verrà eliminato automaticamente dasharedTestTeardown
. - Se definisci
this.workspace
per la prima volta in una suite interna (ovvero, non lo hai definito nella suite più esterna), devi manualmente eliminalo chiamandoworkspaceTeardown.call(this, this.workspace)
durante lo smantellamento di quella suite. - Se definisci
this.workpace
nella suite più esterna, ma poi ridefinisci in una suite di test interna, devi prima richiamareworkspaceTeardown.call(this, this.workspace)
prima di ridefinire per eliminare lo spazio di lavoro originale definito nella suite di primo livello. Devi anche eliminare manualmente il nuovo valore chiamando di nuovoworkspaceTeardown.call(this, this.workspace)
nel teardown di questa suite interna.
- Se definisci
Struttura del test
I test delle unità di solito seguono una struttura prestabilita, che può essere riassunta come organizzare, agire, dichiarare.
- Organizza: configura lo stato del mondo e le eventuali condizioni necessarie per il comportamento in fase di test.
- Azione: chiama il codice in test per attivare il comportamento in esame.
- Asserzione: fai affermazioni sul valore restituito o sulle interazioni con di oggetti simulati al fine di verificarne la correttezza.
In un semplice test, potrebbe non esserci alcun comportamento da organizzare e l'azione e le fasi di asserzione possono essere combinate incorporando la chiamata al codice sottoposto a test l'asserzione. Nei casi più complessi, i test saranno più leggibili se a queste tre fasi.
Ecco un esempio di file di test (semplificato rispetto a quello reale).
suite('Flyout', function() {
setup(function() {
sharedTestSetup.call(this);
this.toolboxXml = document.getElementById('toolbox-simple');
this.workspace = Blockly.inject('blocklyDiv',
{
toolbox: this.toolboxXml
});
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('simple flyout', function() {
setup(function() {
this.flyout = this.workspace.getFlyout();
});
test('y is always 0', function() {
// Act and assert stages combined for simple test case
chai.assert.equal(this.flyout.getY(), 0, 'y coordinate in vertical flyout is 0');
});
test('x is right of workspace if flyout at right', function() {
// Arrange
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewWidth: 100,
});
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_RIGHT;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_RIGHT;
// Act
var x = this.flyout.getX();
// Assert
chai.assert.equal(x, 100, 'x is right of workspace');
});
});
});
Aspetti importanti di questo esempio:
- Una suite può contenere altre suite con metodi
setup
eteardown
aggiuntivi. - Ogni suite e ogni test ha un nome descrittivo.
- Le asserzioni Chai vengono utilizzate per fare affermazioni sul codice.
- Puoi fornire un argomento stringa facoltativo che verrà visualizzato se test non riuscito. In questo modo è più facile eseguire il debug dei test non funzionanti.
- L'ordine dei parametri è
chai.assert.equal(actualValue, expectedValue, optionalMessage)
. Se invertiactual
eexpected
, i messaggi di errore non hanno senso.
- Sinon viene usato per eseguire lo stubing dei metodi quando non si vuole chiamare il codice reale. Nella
questo esempio, non vogliamo chiamare la funzione delle metriche reali perché
non è pertinente per questo test. Ci interessa solo come vengono utilizzati i risultati
il metodo sottoposto a test. Sinon sostituisce la funzione
getMetrics
in modo da restituire una risposta predefinita che possiamo verificare facilmente nelle nostre asserzioni di test. - I metodi
setup
per ogni suite devono contenere solo una configurazione generica che si applica a tutti i test. Se un test per un particolare comportamento si basa su una una determinata condizione, deve essere chiaramente indicata nel test.
Test di debug
- Puoi aprire i test in un browser e utilizzare gli strumenti per sviluppatori per impostare punti di interruzione e verifica se i test non riescono inaspettatamente (o passare inaspettatamente!).
Imposta
.only()
o.skip()
su un test o una suite per eseguire solo quel set di test o salta un test. Ad esempio:suite.only('Workspace', function () { suite('updateToolbox', function () { test('test name', function () { // ... }); test.skip('test I don’t care about', function () { // ... }); }); });
Ricordati di rimuoverli prima di eseguire il commit del codice.
Test del generatore di blocchi
Ogni blocco ha i propri test delle unità. Questi test verificano che i blocchi generino codice che funzioni come previsto.
- Carica
tests/generators/index.html
in Firefox o Safari. Tieni presente che Chrome e Opera presentano limitazioni di sicurezza che impediscono il caricamento dei test dal file "file://" locale di sistema (problemi 41024 e 47416). - Scegli la parte pertinente del sistema da testare dal menu a discesa e fai clic su "Carica". I blocchi dovrebbero apparire nell'area di lavoro.
- Fai clic su "JavaScript".
Copia ed esegui il codice generato in una console JavaScript. Se l'output termina con "OK", il test è stato superato. - Fai clic su "Python".
Copia ed esegui il codice generato in un interprete Python. Se l'output termina con "OK", il test è stato superato. - Fai clic su "PHP".
Copia ed esegui il codice generato in un interprete PHP. Se l'output termina con "OK", il test è stato superato. - Fai clic su "Lua".
Copia ed esegui il codice generato in un interprete Lua. Se l'output termina con "OK", il test è stato superato. - Fai clic su "Dart".
Copia ed esegui il codice generato in un interprete Dart. Se l'output termina con "OK", il test è stato superato.
Modificare i test del generatore a blocchi
- Carica
tests/generators/index.html
in un browser. - Scegli la parte pertinente del sistema dal menu a discesa e fai clic su "Carica". Nell'area di lavoro dovrebbero essere visualizzati i blocchi.
- Apporta eventuali modifiche o aggiunte ai blocchi.
- Fai clic su "XML".
- Copia il codice XML generato nel file appropriato in
tests/generators/
.