Po zmianie lub dodaniu kodu należy uruchomić istniejące testy jednostkowe oraz rozważyć napisanie kolejnych. Wszystkie testy są wykonywane na nieskompresowanych wersjach kodu.
Wyróżniamy 2 zestawy testów jednostkowych: testy JS i testy generatora bloków.
Testy JS
Testy JS sprawdzają działanie wewnętrznych funkcji JavaScriptu w rdzeniu Blockly. Testy jednostkowe przeprowadzamy za pomocą narzędzia Mocha, Sinon do wycinka zależności, oraz Chai, aby aserować kod.
Testy przeprowadzane
Zarówno w blockly, jak i w blockly-samples polecenie npm run test
uruchamia testy jednostkowe. W Blockly zostaną też uruchomione inne testy, takie jak linting i kompilacja. Możesz też otworzyć tests/mocha/index.html
w przeglądarce, aby interaktywnie uruchomić wszystkie testy mocha.
Testy pisania
Testy przeprowadzamy za pomocą interfejsu Mocha TDD. Testy są grupowane w pakiety, które mogą zawierać dodatkowe podpakiety lub testy. Zazwyczaj każdy komponent Blockly (np. toolbox
lub workspace
) ma własny plik testowy, który zawiera co najmniej 1 test. Każdy apartament może mieć setup
i teardown
która będzie wywoływana odpowiednio przed i po każdym teście w danym
.
Pomocnicze narzędzia testowe
W przypadku Blockly jest dostępnych wiele funkcji pomocniczych, które mogą okazać się przydatne, z pisania testów. Znajdziesz je w blokach podstawowych i w przykładach w Blockly.
Funkcje pomocnicze obejmują sharedTestSetup
i sharedTestTeardown
, które
są wymagane przed wykonaniem testu i po nim (patrz Wymagania)
).
sharedTestSetup
:
- Konfiguruje fałszywe minutniki Sinon (w niektórych testach musisz użyć
this.clock.runAll
). - Stubs Blockly.Events.fire uruchamia się natychmiast (można skonfigurować).
- Konfiguruje automatyczne czyszczenie typów bloków zdefiniowanych w elementach
defineBlocksWithJsonArray
. - Deklaruje kilka właściwości kontekstu
this
, które mają być dostępne:this.clock
(nie należy go jednak przywracać, ponieważ może to spowodować problemy wsharedTestTeardown
)this.eventsFireStub
this.sharedCleanup
(do użycia zaddMessageToCleanup
iaddBlockTypeToCleanup
) (UWAGA: jeśli blok został zdefiniowany za pomocą elementudefineBlocksWithJsonArray
, nie musisz używać elementuaddBlockTypeToCleanup
).
Funkcja ma 1 opcjonalny parametr options
, który służy do konfigurowania. Obecnie
jest używane tylko do określenia, czy należy zawrzeć fragment Blockly.Events.fire
, który ma zostać uruchomiony
natychmiast (domyślnie jest to skrócony).
sharedTestTeardown
:
- Usuwa obszar roboczy
this.workspace
(w zależności od tego, gdzie został zdefiniowany, (więcej informacji znajdziesz w sekcji „Wymagania dotyczące testów”). - Przywraca wszystkie wycinki.
- Czyści wszystkie typy bloków dodanych za pomocą
defineBlocksWithJsonArray
iaddBlockTypeToCleanup
. - Czyści wszystkie wiadomości dodane przez
addMessageToCleanup
.
Wymagania testu
- Każdy test musi wywoływać metodę
sharedTestSetup.call(this);
jako pierwszy wiersz w funkcji konfiguracji pakietu zewnętrznego isharedTestTeardown.call(this);
jako ostatniego wiersza dezaprobaty pakietu dla pliku. - Jeśli potrzebujesz workspace z ogólnym zestawem narzędzi, możesz użyć jednego z wstępnie skonfigurowanych zestawów narzędzi w teście
index.html
. Przykład znajdziesz poniżej. - Urządzenie
this.workspace
należy wyrzucić w odpowiedni sposób. W większości testów określić funkcjęthis.workspace
w najbardziej zewnętrznym pakiecie i używać jej we wszystkich kolejnych testowania, ale w niektórych przypadkach można je zdefiniować lub przeformułować, (na przykład jeden z testów wymaga obszaru roboczego z innymi opcjami niż w pierwotnej konfiguracji). Po zakończeniu testu należy go wyrzucić.- Jeśli zdefiniujesz funkcję
this.workspace
w najbardziej zewnętrznym pakiecie i nigdy nie zmienisz definicji nie musisz nic więcej robić. Zostanie on automatycznie usunięty przezsharedTestTeardown
. - Jeśli określisz
this.workspace
po raz pierwszy w apartamencie wewnętrznym (tj. nie została ona zdefiniowana w najbardziej zewnętrznym pakiecie), musisz ręcznie aby je utylizować, wywołującworkspaceTeardown.call(this, this.workspace)
w czasie demontażu tej aranżacji. - Jeśli zdefiniujesz
this.workpace
w zewnętrznym zbiorze testów, ale potem zdefiniujesz go ponownie w wewnętrznym zbiorze testów, musisz najpierw wywołaćworkspaceTeardown.call(this, this.workspace)
przed ponownym zdefiniowaniem, aby usunąć oryginalną przestrzeń roboczą zdefiniowaną w zbiorze najwyższego poziomu. Ty musi też ręcznie usunąć nową wartość, wywołującworkspaceTeardown.call(this, this.workspace)
ponownie w komponencie apartament wewnętrzny.
- Jeśli zdefiniujesz funkcję
Struktura testu
Testy jednostkowe zwykle mają ustaloną strukturę, którą można podsumować jako uporządkuj, wykonaj, sprawdź.
- Rozmieść: określ stan świata i wszelkie niezbędne warunki do badanego zachowania.
- Działanie: wywołaj testowany kod, aby aktywować testowane działanie.
- Zakładanie: twierdzenie dotyczące wartości zwracanej lub interakcji z udawanymi obiektami w celu sprawdzenia poprawności.
W prostym teście może nie być żadnego zachowania do zorganizowania, a działanie i Etapy żądania można łączyć przez wbudowanie wywołania do testowanego kodu w funkcji asercji. W bardziej złożonych przypadkach testy będą bardziej czytelne do tych 3 etapów.
Oto przykładowy plik testowy (uproszczony w rzeczywistości).
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');
});
});
});
Co warto wiedzieć z tego przykładu:
- W apartamencie mogą znajdować się inne apartamenty z dodatkowymi obiektami
setup
iteardown
. - Każdy zestaw i każdy test ma nazwę opisową.
- Asercje czai są używane do formułowania asercji dotyczących kodu.
- Możesz podać opcjonalny argument ciągu znaków, który będzie wyświetlany, jeśli test się nie powiedzie. Ułatwia to debugowanie niedziałających testów.
- Kolejność parametrów to
chai.assert.equal(actualValue, expectedValue, optionalMessage)
. Jeśli zamieniszactual
iexpected
: komunikaty o błędach nie będą miały sensu.
- Sinon służy do tworzenia metod typu stub, gdy nie chcesz wywoływać rzeczywistego kodu. W tym przykładzie nie chcemy wywoływać funkcji prawdziwych danych, ponieważ nie jest ona istotna dla tego testu. Interesuje nas tylko sposób wykorzystania wyników przez testowaną metodę. Sinon łączy funkcję
getMetrics
, aby zwrócić szablon odpowiedzi, który możemy łatwo sprawdzić w asercjach testowych. - Metody
setup
dla każdego pakietu powinny zawierać tylko ogólną konfigurację, która dotyczy wszystkich testów. Jeśli test określonego zachowania opiera się na określony warunek musi być wyraźnie określony w odpowiednich test.
Testy debugowania
- Możesz otworzyć testy w przeglądarce i użyć narzędzi dla programistów, aby ustawić punkty kontrolne i sprawdzić, czy testy niespodziewanie się nie powielają (lub niespodziewanie przechodzą).
Ustaw
.only()
lub.skip()
w teście lub pakiecie, aby uruchomić tylko ten zestaw testów. lub pomiń test. Na przykład:suite.only('Workspace', function () { suite('updateToolbox', function () { test('test name', function () { // ... }); test.skip('test I don’t care about', function () { // ... }); }); });
Pamiętaj, aby usunąć je przed zatwierdzeniem kodu.
Testy generatorów blokowych
Każdy blok ma własne testy jednostkowe. Testy te potwierdzają, że bloki generują niż funkcje zgodne z przeznaczeniem.
- Otwórz
tests/generators/index.html
w Firefoksie lub Safari. Pamiętaj, że Chrome i Opera mają ograniczenia bezpieczeństwa, które uniemożliwiają ładowanie testów z lokalnego pliku „file://” system (problemy 41024) i 47416). - W menu kliknij odpowiednią część systemu, którą chcesz przetestować, a następnie kliknij „Wczytaj”. Blokady powinny pojawić się w obszarze roboczym.
- Kliknij „JavaScript”.
Skopiuj i uruchom wygenerowany kod w konsoli JavaScriptu. Jeśli dane wyjściowe zakończą się „OK”, oznacza to, że test został zaliczony. - Kliknij „Python”.
Skopiuj i uruchom wygenerowany kod w interpreterze Pythona. Jeśli dane wyjściowe kończą się na „OK”, test został zaliczony. - Kliknij „PHP”.
Skopiuj wygenerowany kod i uruchom go w interpreterze PHP. Jeśli w wynikach pojawi się „OK”, test zakończył się powodzeniem. - Kliknij „Lua”.
Skopiuj i uruchom wygenerowany kod w interpreterze Lua. Jeśli dane wyjściowe kończą się na „OK”, test został zaliczony. - Kliknij „Dart”.
Skopiuj i uruchom wygenerowany kod w interpreterze Dart. Jeśli w wynikach pojawi się „OK”, test zakończył się powodzeniem.
Edytowanie testów generatora bloków
- Wczytaj
tests/generators/index.html
w przeglądarce. - Wybierz z menu odpowiednią część systemu i kliknij „Wczytaj”. Blokady powinny pojawić się w obszarze roboczym.
- Wprowadź zmiany lub uzupełnij bloki.
- Kliknij „XML”.
- Skopiuj wygenerowany plik XML do odpowiedniego pliku w programie
tests/generators/
.