Dopo aver modificato o aggiunto il codice, ti consigliamo di eseguire i test delle unità esistenti e valutare la possibilità di crearne altri. Tutti i test vengono eseguiti sulle versioni non compresse del codice.
Esistono due gruppi di test delle unità: test JS e test del generatore a blocchi.
Test JS
I test JS confermano il funzionamento delle funzioni JavaScript interne nel core di Blockly. Utilizziamo Mocha per eseguire i test delle unità, Sinon per stub delle dipendenze e Chai per fare asserzioni sul codice.
Test in esecuzione
Sia negli esempi a blocchi che in quelli a blocchi, npm run test
eseguirà i test delle unità. In
blocco, verranno eseguiti anche altri test, come analisi tramite lint e 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 Mocha TDD per eseguire i test. I test sono organizzati in suite,
che possono contenere sottosuite e/o test aggiuntivi. In genere, ogni componente di Blockly (come 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 nella suite.
Aiutanti per il test
Abbiamo una serie di funzioni helper specifiche di Blockly che possono essere utili durante la scrittura dei test. Sono disponibili in core e in blockly-samples.
Le funzioni helper includono sharedTestSetup
e sharedTestTeardown
, che
devono essere chiamati prima e dopo i test (consulta la sezione Requisiti).
sharedTestSetup
:
- Configura timer sinon falsi (in alcuni test dovrai utilizzare
this.clock.runAll
). - Stubs Blockly.Events.fire si attivi immediatamente (configurabile).
- Consente di configurare la pulizia automatica dei blockTypes definiti tramite
defineBlocksWithJsonArray
. - Dichiara nel contesto
this
alcune proprietà che dovrebbero essere accessibili:this.clock
(ma non deve essere ripristinata 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. Attualmente, viene utilizzato solo per determinare se simulare Blockly.Events.fire
affinché venga attivato immediatamente (lo stub viene attivato per impostazione predefinita).
sharedTestTeardown
:
- Consente di eliminare l'area di lavoro
this.workspace
(a seconda di dove è stata definita, consulta la sezione Requisiti per il test per saperne di più). - Ripristina tutti gli stub.
- Ripulisce tutti i tipi di blocco aggiunti tramite
defineBlocksWithJsonArray
eaddBlockTypeToCleanup
. - Ripulisce tutti i messaggi aggiunti tramite
addMessageToCleanup
.
Requisiti per il test
- Ogni test deve richiamare
sharedTestSetup.call(this);
come prima riga nella configurazione della suite più esterna esharedTestTeardown.call(this);
come ultima riga nella rimozione della suite più esterna per un file. - Se hai bisogno di un'area di lavoro con una serie di strumenti generici, puoi utilizzare una delle
cassette degli strumenti preimpostate
nel test
index.html
. Di seguito è riportato un esempio. - Devi smaltire correttamente
this.workspace
. Nella maggior parte dei test, definiscithis.workspace
nella suite più esterna e lo utilizzi per tutti i test successivi, ma in alcuni casi puoi definirlo o ridefinire in una suite interna (ad esempio, uno dei test richiede un'area di lavoro con opzioni diverse da quelle configurate inizialmente). Deve essere smaltito al termine del test.- Se definisci
this.workspace
nella suite più esterna e non lo ridefinisci mai, non sono necessarie ulteriori azioni. 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 eliminarlo manualmente chiamandoworkspaceTeardown.call(this, this.workspace)
nell'eliminazione di quella suite. - Se definisci
this.workpace
nella suite più esterna, ma poi lo ridefinisci in una suite di test interna, devi prima chiamareworkspaceTeardown.call(this, this.workspace)
prima di ridefinire la suite per eliminare l'area di lavoro originale definita nella suite di primo livello. Devi inoltre eliminare manualmente il nuovo valore chiamando di nuovoworkspaceTeardown.call(this, this.workspace)
nello smontaggio di questa suite interna.
- Se definisci
Struttura di test
I test delle unità di solito seguono una struttura impostata, che può essere riassunta come disporre, agire, asserire.
- Disponi: imposta lo stato del mondo e le condizioni necessarie per il comportamento in fase di test.
- Agisci: chiama il codice sottoposto a test per attivare il comportamento da testare.
- Dichiarazione: fai delle asserzioni sul valore restituito o sulle interazioni con oggetti fittizi per verificarne la correttezza.
In un semplice test potrebbe non esserci alcun comportamento da organizzare e le fasi di azione e dichiarazione possono essere combinate incorporando la chiamata al codice in fase di test nell'assertion. Per i casi più complessi, i test saranno più leggibili se segui queste tre fasi.
Di seguito è riportato un file di test di esempio (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 da considerare in questo esempio:
- Una suite può contenere altre suite che dispongono di metodi
setup
eteardown
aggiuntivi. - Ogni suite e test ha un nome descrittivo.
- Le asserzioni chai vengono utilizzate per fare asserzioni sul codice.
- Puoi fornire un argomento stringa facoltativo che verrà visualizzato se il test ha esito negativo. In questo modo è più facile eseguire il debug dei test non funzionanti.
- L'ordine dei parametri è
chai.assert.equal(actualValue, expectedValue, optionalMessage)
. Se cambiactual
eexpected
, i messaggi di errore non avranno senso.
- Sinon viene utilizzato per eseguire la stub dei metodi quando non si vuole chiamare il codice reale. In questo esempio, non vogliamo chiamare la funzione delle metriche reali perché non è pertinente per questo test. Ci interessa solo come i risultati vengono
utilizzati dal metodo in fase di test. Sinon esegue lo stub della funzione
getMetrics
per restituire una risposta predefinita che possiamo facilmente verificare nelle nostre asserzioni di test. - I metodi
setup
per ogni suite devono contenere solo la configurazione generica che si applica a tutti i test. Se un test per un determinato comportamento si basa su una determinata condizione, questa condizione deve essere chiaramente indicata nel test pertinente.
Test di debug
- Puoi aprire i test in un browser e utilizzare gli strumenti per sviluppatori per impostare i punti di interruzione e verificare se i test non riescono inaspettatamente (o passano inaspettatamente).
Imposta
.only()
o.skip()
su un test o una suite per eseguire solo quell'insieme di test oppure ignora 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 confermare il codice.
Test generatori a blocchi
Ogni blocco ha i propri test delle unità. Questi test verificano che i blocchi generino codice anziché le funzioni come previsto.
- Carica
tests/generators/index.html
in Firefox o Safari. Tieni presente che Chrome e Opera hanno limitazioni di sicurezza che impediscono il caricamento dei test dal sistema locale "file://" (problemi 41024 e 47416). - Scegli la parte pertinente del sistema da testare dal menu a discesa e fai clic su "Carica". I blocchi dovrebbero essere visualizzati nello spazio 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.
Modifica dei test dei generatori 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". I blocchi dovrebbero essere visualizzati nello spazio di lavoro.
- Apporta eventuali modifiche o aggiunte ai blocchi.
- Fai clic su "XML".
- Copia il codice XML generato nel file appropriato in
tests/generators/
.