Zautomatyzowane testy to zasadniczo kod, który generuje lub powoduje błąd, jeśli coś poszło nie tak. Większość bibliotek i platform testowych zapewnia różne elementów podstawowych, które ułatwiają pisanie testów.
Jak wspomnieliśmy w poprzedniej sekcji, te elementy podstawowe niemal zawsze zawierają wyznaczania niezależnych testów (nazywanych przypadkami testowymi) i dostarczania asercji. Asercje to sposób połączenia sprawdzania wyniku z przesyłaniem żądania gdy coś jest nie tak i można go uznać za podstawowy czyli testowania elementów podstawowych.
Ta strona zawiera ogólne podejście do tych elementów podstawowych. Wybrana przez Ciebie platforma prawdopodobnie ma coś takiego, ale nie jest to dokładne odniesienie.
Na przykład:
import { fibonacci, catalan } from '../src/math.js';
import { assert, test, suite } from 'a-made-up-testing-library';
suite('math tests', () => {
test('fibonacci function', () => {
// check expected fibonacci numbers against our known actual values
// with an explanation if the values don't match
assert.equal(fibonacci(0), 0, 'Invalid 0th fibonacci result');
assert.equal(fibonacci(13), 233, 'Invalid 13th fibonacci result');
});
test('relationship between sequences', () => {
// catalan numbers are greater than fibonacci numbers (but not equal)
assert.isAbove(catalan(4), fibonacci(4));
});
test('bugfix: check bug #4141', () => {
assert.isFinite(fibonacci(0)); // fibonacci(0) was returning NaN
})
});
W tym przykładzie tworzona jest grupa testów (czasami nazywana pakietem) o nazwie „matematyka”. (testy) i zdefiniowano 3 niezależne przypadki testowe, w których każdy przeprowadza pewne asercje. Takie przypadki testowe można zwykle rozwiązać lub przeprowadzić, na przykład przez flagi filtra w narzędziu testowym.
Asystent asercji jako elementy podstawowe
Większość platform testowych, w tym Vitest, zawiera zbiór asercji
w obiekcie assert
, które pozwalają szybko sprawdzić zwracane wartości,
z niektórymi oczekiwaniami. To oczekiwanie często jest określane jako „znane dobra”.
. W poprzednim przykładzie wiemy, że trzynasta liczba Fibonacciego powinna wynosić
233, więc możemy potwierdzić, że to bezpośrednio za pomocą assert.equal
.
Możesz też mieć oczekiwania, że wartość ma określoną postać większą niż inna wartość lub mają inną właściwość. Ten kurs nie: obejmują pełną gamę pomocników asercji, zawsze przeprowadzaj przynajmniej te podstawowe kontrole:
„Prawda” kontrola, często opisana jako „OK” sprawdza, czy warunek jest spełniony tak jak można napisać
if
, który sprawdza, czy coś się udało Zgadza się. Zwykle podaje się ją jakoassert(...)
lubassert.ok(...)
, przyjmuje pojedynczą wartość plus opcjonalny komentarz.Sprawdź równość, np. w przykładzie matematycznym, w którym oczekujesz zwracaną wartość lub stan obiektu, aby równać się znanej dobrej wartości. Są one przeznaczone dla równość podstawowa (np. w przypadku liczb i ciągów znaków) lub równość referencyjna (to ten sam obiekt). W głowie się nie mieści, to jest po prostu „prawda” zaznacz z porównaniem
==
lub===
.- W języku JavaScript różni się loczna (
==
) i ścisła (===
) równość. Większość bibliotek testowych udostępnia metodyassert.equal
iassert.strictEqual
.
- W języku JavaScript różni się loczna (
Szczegółowa kontrola równości, która obejmuje sprawdzanie równości zawartości obiektów, tablic i innych bardziej złożonych typów danych, a także dzięki wewnętrznej logice, aby przemierzać obiekty i je porównywać. To ważne: bo JavaScript nie ma wbudowanego sposobu na porównywanie zawartości dwóch obiektów lub tablic. Na przykład
[1,2,3] == [1,2,3]
ma zawsze wartość fałsz. Testuj platformy często zawierają pomocnikideepEqual
lubdeepStrictEqual
.
Asystent porównawczy asercji, który porównuje 2 wartości (a nie tylko test „prawdziwość”) zwykle przyjmuje się 2 lub 3 argumenty:
- Rzeczywista wartość wygenerowana na podstawie testowanego kodu lub opisująca do weryfikacji.
- Wartość oczekiwana, zwykle zakodowana na stałe (np. liczba dosłowna lub ciąg znaków).
- Opcjonalny komentarz opisujący, co jest spodziewane lub co mogło zostać nieskuteczne. który zostanie uwzględniony w przypadku niepowodzenia tej linii.
Powszechną praktyką jest też łączenie asercji w celu utworzenia różnych sprawdza się, ponieważ rzadko można prawidłowo potwierdzić stan przez system. Na przykład:
test('JWT parse', () => {
const json = decodeJwt('eyJieSI6InNhbXRob3Ii…');
assert.ok(json.payload.admin, 'user should be admin');
assert.deepEqual(json.payload.groups, ['role:Admin', 'role:Submitter']);
assert.equal(json.header.alg, 'RS265')
assert.isAbove(json.payload.exp, +new Date(), 'expiry must be in future')
});
Vitest używa biblioteki asercji Chai wewnętrznie, aby zapewnić swoim pomocnikom asercji, i przydatne może być analizowanie odniesienie do tego, które asercje i pomocniki mogą pasować do Twojego kodu.
Asercje o biegłości i BDD
Niektórzy deweloperzy preferują styl asercji, który można nazwać opartym na zachowaniach.
(BDD) lub
Styl Fluent
asercji. Są również nazywane „oczekiwaniami”. ponieważ punkt wejścia
sprawdzanie oczekiwań to metoda o nazwie expect()
.
Spodziewaj się, że elementy pomocnicze będą zachowywać się tak samo jak asercje zapisane jako metoda prosta
takie jak assert.ok
lub assert.strictDeepEquals
, ale niektórzy deweloperzy uznają je za czytelniejsze.
Potwierdzenie BDD może wyglądać tak:
// A failure here would generate "Expect result to be an array that does include 42"
const result = await possibleMeaningsOfLife();
expect(result).to.be.an('array').that.does.include(42);
// or a simpler form
expect(result).toBe('array').toContainEqual(42);
// the same in assert might be
assert.typeOf(result, 'array', 'Expected the result to be an array');
assert.include(result, 42, 'Expected the result to include 42');
Ten styl asercji działa dzięki metodzie zwanej łańcuchem metod,
w którym obiekt zwrócony przez funkcję expect
może być stale połączony w łańcuch,
kolejnych wywołań metod. Niektóre części rozmowy, w tym to.be
i that.does
w poprzednim przykładzie nie mają żadnej funkcji i są uwzględniane tylko w celu wywołania
być bardziej czytelne i potencjalnie generować automatyczny komentarz, jeśli test
niepowodzenie. (W szczególności funkcja expect
zwykle nie obsługuje opcjonalnego komentarza, ponieważ
łańcuch powinien jasno opisywać błąd).
Wiele platform testowych obsługuje zarówno twierdzenia Fluent/BDD, jak i zwykłe asercje. Vitest, na przykład eksportuje zarówno Chai ma nieco bardziej zwięzłe podejście do BDD. Jest z drugiej strony zawiera tylko oczekiwany wynik .
Grupuj testy w plikach
Podczas pisania testów zwykle umieszczamy niejawne grupowanie. niż wszystkie testy w jednym pliku, często zapisuje się je w wielu różnych . Uczestnicy testu zwykle wiedzą, że plik jest przeznaczony do testów, ponieważ wstępnie zdefiniowanego filtra lub wyrażenia regularnego – na przykład vitest obejmuje wszystkie pliki w projekcie, które mają rozszerzenie „.test.jsx”; lub „.spec.ts” („.test” i „.spec” oraz kilka prawidłowych rozszerzeń).
Testy komponentów znajdują się zwykle w pliku równorzędnym z testowanym komponentem. jak w następującej strukturze katalogów:
Testy jednostkowe również są umieszczane obok testowanego kodu. Kompleksowe testy mogą znajdować się w osobnych plikach, a testy integracji mogą nawet i umieszczać je w osobnych folderach. Takie struktury mogą być pomocne, złożone przypadki testowe coraz częściej wymagają własnych plików pomocniczych, takich jak obsługują biblioteki potrzebne tylko do testów.
Grupowe testy w plikach
Jak wspomnieliśmy w poprzednich przykładach, często przeprowadza się testy w obrębie wywołania funkcji
suite()
, który grupuje testy skonfigurowane za pomocą narzędzia test()
. Mieszkania nie są zwykle
samodzielnie testują, ale pomagają stworzyć strukturę, grupując powiązane testy.
lub celów, wywołując przekazaną metodę. W przypadku test()
przekazana metoda opisuje
na samym początku testu.
Podobnie jak w przypadku asercji, w Fluent/BDD istnieje dość standardowy odpowiednik grupowania testów. Poniżej znajdziesz porównanie kilku typowych przykładów:
// traditional/TDD
suite('math tests', () => {
test('handle zero values', () => {
assert.equal(fibonacci(0), 0);
});
});
// Fluent/BDD
describe('math tests', () => {
it('should handle zero values', () => {
expect(fibonacci(0)).toBe(0);
});
})
W większości platform suite
i describe
działają podobnie, podobnie jak test
i
it
, w odróżnieniu od większych różnic między używaniem wartości expect
i assert
do pisania asercji.
Inne narzędzia stosują nieco inne podejście do porządkowania pakietów i testów. Dla:
na przykład wbudowany mechanizm uruchamiania testów w Node.js obsługuje zagnieżdżanie wywołań funkcji test()
w celu
niejawnie utworzyć hierarchię testową. Vitest zezwala jednak tylko na ten rodzaj
zagnieżdżenie za pomocą suite()
i nie uruchomi żadnego elementu test()
zdefiniowanego w innym obiekcie test()
.
Podobnie jak w przypadku asercji, pamiętaj, że dokładne połączenie grupowania stosowane przez Twój stos technologiczny nie są aż tak ważne. Tematy poruszane w tym kursie to abstrakcyjne, ale musisz przemyśleć, jak będą się one stosować szeroki wybór narzędzi.
Metody cyklu życia
Jednym z powodów, dla których warto grupować testy, nawet pośrednio na najwyższym poziomie w obrębie jest udostępnienie metod konfiguracji i dezaktywacji, które działają przy każdym teście, dla grupy testów. Większość platform udostępnia 4 metody:
Dla każdej funkcji „test()” lub „it()” | Raz na pakiet | |
---|---|---|
Przed uruchomieniami testów | „beforeEach()” | `beforeAll()` |
Po przeprowadzeniu testów | „afterEach()” | „afterAll()” |
Możesz na przykład wstępnie wypełnić wirtualną bazę danych użytkowników przed każdym a potem usuń go:
suite('user test', () => {
beforeEach(() => {
insertFakeUser('bob@example.com', 'hunter2');
});
afterEach(() => {
clearAllUsers();
});
test('bob can login', async () => { … });
test('alice can message bob', async () => { … });
});
Pozwala to uprościć testy. Możesz udostępnić wspólną konfigurację i w kodzie dezaktywacji, zamiast powielać go w każdym teście. Dodatkowo, jeśli Sam kod konfiguracji i dezaktywacji powoduje błąd, który może oznaczać, które nie są związane z niepowodzeniem samych testów.
Porady ogólne
Oto kilka wskazówek, o których warto pamiętać, analizując te elementy podstawowe.
Przewodniki po elementach podstawowych
Pamiętaj, że narzędzia i elementy podstawowe dostępne tutaj i na kilku kolejnych stronach nie będą ściśle pasuje do Vitest, Jest, Mocha, Web Testner lub innego określonych ram. Vitest jest naszym ogólnym przewodnikiem, ale pamiętaj, zgodnie z wybranym schematem.
Mieszaj i dopasowuj asercje w razie potrzeby
Testy to z reguły kod, który może powodować błędy. Każdy biegacz zapewni
zwykły (prawdopodobnie test()
), aby opisać różne przypadki testowe.
Jeśli jednak ten biegacz udostępnia również pomocniki assert()
, expect()
i asercji,
pamiętaj, że ta część dotyczy wygody. Można ją pominąć, jeśli
co trzeba. Możesz uruchomić dowolny kod, który może generować błąd, w tym inny kod
biblioteki asercji lub starą dobrą instrukcję if
.
Konfiguracja IDE może uratować życie
Zapewnienie w IDE, np. VSCode, dostępu do autouzupełniania
dokumentacja wybranego narzędzia testowego może zwiększyć Twoją wydajność. Dla:
istnieje ponad 100 metod na assert
w potwierdzeniu Chai
oraz posiadanie dokumentacji
wyświetlane w tekście,
mogą być wygodne.
Może to być szczególnie ważne w przypadku niektórych platform testowych wypełniających w globalnej przestrzeni nazw i metodami testowania. To subtelna różnica, ale można często korzystać z bibliotek testowych bez ich importowania, jeśli są automatycznie dodane do globalnej przestrzeni nazw:
// some.test.js
test('using test as a global', () => { … });
Zalecamy importowanie pomocników, nawet jeśli są one obsługiwane automatycznie,
ponieważ daje to IDE jasny sposób wyszukiwania tych metod. (Być może masz
napotkał ten problem podczas budowania React, ponieważ niektóre bazy kodu
React
– globalne, ale niektóre nie – muszą zostać zaimportowane we wszystkich plikach za pomocą
React.)
// some.test.js
import { test } from 'vitest';
test('using test as an import', () => { … });