Nachdem Sie Code geändert oder hinzugefügt haben, sollten Sie vorhandene Unit-Tests ausführen und weitere schreiben. Alle Tests werden mit den nicht komprimierten Codeversionen ausgeführt.
Es gibt zwei Sätze von Einheitentests: JS-Tests und Blockgenerator-Tests.
JS-Tests
Mit den JS-Tests wird der Betrieb interner JavaScript-Funktionen im Kern von Blockly bestätigt. Wir verwenden Mocha zum Ausführen von Einheitentests, Sinon zum Erstellen von Stub-Abhängigkeiten und Chai, um Assertions für den Code zu erstellen.
Laufende Tests
Sowohl in Blockly- als auch in Blockly-Stichproben führt npm run test
die Einheitentests aus. In Blockly werden dadurch auch andere Tests wie Lint und Kompilierung ausgeführt. Sie können tests/mocha/index.html
auch in einem Browser öffnen, um alle Mocha-Tests interaktiv auszuführen.
Tests schreiben
Wir verwenden die Mocha-TDD-Oberfläche, um Tests auszuführen. Tests sind in Suiten organisiert, die sowohl zusätzliche Untergruppen als auch Tests enthalten können. Im Allgemeinen hat jede Blockly-Komponente (z. B. toolbox
oder workspace
) eine eigene Testdatei, die eine oder mehrere Suiten enthält. Jede Suite kann eine setup
- und eine teardown
-Methode haben, die vor bzw. nach jedem Test in dieser Suite aufgerufen werden.
Testhilfen
Es gibt eine Reihe von Blockly-spezifischen Hilfsfunktionen, die beim Schreiben von Tests nützlich sein können. Sie finden sie in core und in blockly-samples.
Zu den Hilfsfunktionen gehören sharedTestSetup
und sharedTestTeardown
, die vor und nach den Tests aufgerufen werden müssen (siehe Abschnitt „Anforderungen“).
sharedTestSetup
:
- Richtet imaginäre Timer ein (in einigen Tests müssen Sie
this.clock.runAll
verwenden). - Stubs für Blockly.Events.fire, die sofort ausgelöst werden (konfigurierbar).
- Hiermit wird die automatische Bereinigung von blockTypes eingerichtet, die über
defineBlocksWithJsonArray
definiert wurden. - Hier werden einige Properties für den
this
-Kontext deklariert, die zugänglich sein sollen:this.clock
(sollte aber nicht wiederhergestellt werden, da dies Probleme insharedTestTeardown
verursachen kann)this.eventsFireStub
this.sharedCleanup
(mitaddMessageToCleanup
undaddBlockTypeToCleanup
verwenden) (HINWEIS: Sie müssenaddBlockTypeToCleanup
nicht verwenden, wenn Sie den Block mitdefineBlocksWithJsonArray
definiert haben)
Die Funktion hat einen optionalen Parameter options
zum Konfigurieren der Einrichtung. Derzeit wird es nur verwendet, um zu bestimmen, ob Blockly.Events.fire
sofort ausgelöst werden soll (standardmäßig wird ein Stub erstellt).
sharedTestTeardown
:
- Löscht den Arbeitsbereich
this.workspace
(je nachdem, wo er definiert wurde, siehe Abschnitt zu Testanforderungen). - Stellt alle Stubs wieder her.
- Alle Blocktypen werden entfernt, die über
defineBlocksWithJsonArray
undaddBlockTypeToCleanup
hinzugefügt wurden. - Alle Nachrichten, die über
addMessageToCleanup
hinzugefügt wurden, werden bereinigt.
Testanforderungen
- Jeder Test muss
sharedTestSetup.call(this);
als erste Zeile in der Einrichtung der äußersten Suite undsharedTestTeardown.call(this);
als letzte Zeile in der Deaktivierung der äußersten Suite für eine Datei aufrufen. - Wenn Sie einen Arbeitsbereich mit einer generischen Toolbox benötigen, können Sie eine der vordefinierten Toolboxen auf dem Test-
index.html
verwenden. Unten finden Sie ein Beispiel. - Sie müssen
this.workspace
ordnungsgemäß entsorgen. In den meisten Tests definieren Siethis.workspace
in der äußersten Suite und verwenden sie für alle nachfolgenden Tests. In einigen Fällen können Sie sie jedoch auch in einer inneren Suite definieren oder neu definieren (z. B. erfordert für einen Ihrer Tests ein Arbeitsbereich mit anderen Optionen als ursprünglich eingerichtet). Sie muss am Ende des Tests entsorgt werden.- Wenn Sie
this.workspace
in der äußersten Suite definieren und nie neu definieren, sind keine weiteren Maßnahmen erforderlich. Sie wird automatisch amsharedTestTeardown
entsorgt. - Wenn Sie
this.workspace
zum ersten Mal in einer inneren Suite definieren (d.h. nicht in der äußersten Suite), müssen Sie es manuell beseitigen, indem SieworkspaceTeardown.call(this, this.workspace)
beim Abbau dieser Suite aufrufen. - Wenn Sie
this.workpace
in der äußersten Suite definieren, sie aber dann in einer inneren Testsuite neu definieren, müssen Sie zuerstworkspaceTeardown.call(this, this.workspace)
aufrufen, bevor Sie sie neu definieren, um den ursprünglichen Arbeitsbereich in der Suite der obersten Ebene zu entfernen. Sie müssen den neuen Wert auch manuell entsorgen, indem SieworkspaceTeardown.call(this, this.workspace)
noch einmal beim Abbau dieser inneren Suite aufrufen.
- Wenn Sie
Teststruktur
Unittests folgen in der Regel einer festgelegten Struktur, die sich zusammenfassen lässt als Anordnung, Ausführung, Bestätigung.
- Anordnen: Legen Sie den Status der Welt und alle erforderlichen Bedingungen für das zu testende Verhalten fest.
- Act (Aktion): Rufen Sie den zu testenden Code auf, um das zu testende Verhalten auszulösen.
- Assert: Sie können Behauptungen über den Rückgabewert oder Interaktionen mit simulierten Objekten aufstellen, um die Richtigkeit zu überprüfen.
Bei einem einfachen Test gibt es möglicherweise kein Verhalten, das eingerichtet werden muss. Die Phasen „Aktion“ und „Bestätigung“ können kombiniert werden, indem der Aufruf des zu testenden Codes in die Bestätigung eingefügt wird. In komplexeren Fällen sind Ihre Tests besser lesbar, wenn Sie diese drei Phasen einhalten.
Hier sehen Sie eine Beispieltestdatei, die vereinfacht ist.
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');
});
});
});
Hinweise zu diesem Beispiel:
- Eine Suite kann andere Suiten mit zusätzlichen
setup
- undteardown
-Methoden enthalten. - Jede Suite und jeder Test hat einen aussagekräftigen Namen.
- Chai-Assertions werden verwendet, um Assertions für den Code zu erstellen.
- Sie können ein optionales Stringargument angeben, das angezeigt wird, wenn der Test fehlschlägt. So lassen sich fehlerhafte Tests leichter beheben.
- Die Reihenfolge der Parameter ist
chai.assert.equal(actualValue, expectedValue, optionalMessage)
. Wenn Sieactual
undexpected
vertauschen, haben die Fehlermeldungen keinen Sinn.
- Sinon wird für Stub-Methoden verwendet, wenn der echte Code nicht aufgerufen werden soll. In diesem Beispiel soll nicht die echte Messwertfunktion aufgerufen werden, da sie für diesen Test nicht relevant ist. Uns geht es nur darum, wie die Ergebnisse von der getesteten Methode verwendet werden. Sinon führt einen Stub für die
getMetrics
-Funktion ein, um eine Antwortvorlage zurückzugeben, die wir leicht in unseren Test-Assertions finden können. - Die
setup
-Methoden für jede Suite sollten nur eine allgemeine Einrichtung enthalten, die für alle Tests gilt. Wenn ein Test für ein bestimmtes Verhalten von einer bestimmten Bedingung abhängt, sollte diese Bedingung im entsprechenden Test klar angegeben sein.
Tests zur Fehlerbehebung
- Sie können die Tests in einem Browser öffnen und mit den Entwicklertools Haltestellen festlegen, um zu prüfen, ob Ihre Tests unerwartet fehlschlagen (oder unerwartet bestehen).
Legen Sie für einen Test oder eine Suite
.only()
oder.skip()
fest, um nur diesen Test bzw. diese Suite auszuführen oder einen Test zu überspringen. Beispiel:suite.only('Workspace', function () { suite('updateToolbox', function () { test('test name', function () { // ... }); test.skip('test I don’t care about', function () { // ... }); }); });
Denken Sie daran, diese zu entfernen, bevor Sie Ihren Code committen.
Blockgeneratortests
Für jeden Block gibt es eigene Unit-Tests. Bei diesen Tests wird überprüft, ob Blöcke Code generieren, der wie vorgesehen funktioniert.
- Lade
tests/generators/index.html
in Firefox oder Safari. Chrome und Opera haben Sicherheitseinschränkungen, die das Laden der Tests aus dem lokalen „file://“-System verhindern (Probleme 41024 und 47416). - Wählen Sie im Drop-down-Menü den entsprechenden Teil des Systems aus, den Sie testen möchten, und klicken Sie auf „Laden“. Blöcke sollten im Arbeitsbereich angezeigt werden.
- Klicken Sie auf „JavaScript“.
Kopieren Sie den generierten Code und führen Sie ihn in einer JavaScript-Konsole aus. Wenn die Ausgabe mit „OK“ endet, ist der Test bestanden. - Klicken Sie auf „Python“.
Kopieren Sie den generierten Code und führen Sie ihn in einem Python-Interpreter aus. Wenn die Ausgabe mit „OK“ endet, war der Test erfolgreich. - Klicken Sie auf "PHP".
Kopieren Sie den generierten Code und führen Sie ihn in einem PHP-Interpreter aus. Wenn die Ausgabe mit „OK“ endet, war der Test erfolgreich. - Klicke auf „Lua“.
Kopieren Sie den generierten Code und führen Sie ihn in einem Lua-Interpreter aus. Wenn die Ausgabe mit „OK“ endet, war der Test erfolgreich. - Klicken Sie auf „Dart“.
Kopieren Sie den generierten Code und führen Sie ihn in einem Dart-Interpreter aus. Wenn die Ausgabe mit „OK“ endet, war der Test erfolgreich.
Blockgenerator-Tests bearbeiten
- Laden Sie
tests/generators/index.html
in einem Browser. - Wählen Sie im Drop-down-Menü den entsprechenden Teil des Systems aus und klicken Sie auf „Laden“. Blöcke sollten im Arbeitsbereich angezeigt werden.
- Nehmen Sie alle gewünschten Änderungen oder Ergänzungen an den Blöcken vor.
- Klicken Sie auf „XML“.
- Kopieren Sie die generierte XML-Datei in die entsprechende Datei in
tests/generators/
.