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.eventsFireStubthis.sharedCleanup(do użycia zaddMessageToCleanupiaddBlockTypeToCleanup) (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ą
defineBlocksWithJsonArrayiaddBlockTypeToCleanup. - 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.workspacenależy wyrzucić w odpowiedni sposób. W większości testów określić funkcjęthis.workspacew 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.workspacew 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.workspacepo 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.workpacew 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
setupiteardown. - 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 zamieniszactualiexpected: 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
setupdla 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.htmlw 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.htmlw 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/.