Funcții care pot eșua
O funcție care poate primi date greșite trebuie să spună acest lucru. Modul obișnuit este să arunce o eroare: la succes funcția își returnează rezultatul, iar la eșec aruncă un Error care explică ce nu a mers bine.
Un test pentru o astfel de funcție trebuie să verifice ambele căi: date corecte returnează valoarea potrivită și nu aruncă nicio eroare, iar date greșite chiar aruncă o eroare — o funcție care acceptă în tăcere date greșite este tot o eroare de program.
assert.throws(fn) este verificarea pentru calea greșită. Pentru o funcție care returnează o promisiune, aceeași verificare se scrie assert.rejects(fn) și se așteaptă cu await.
Calea corectă
Pentru date valide nu ai nimic în plus de scris. Apelezi funcția, apoi compari valoarea. Dacă apelul aruncă totuși o eroare, aruncarea încheie testul de la sine, iar raportul arată eroarea — nu trebuie să verifici acest lucru dinainte.
Date valide, fără eroare
safeDivide(10, 2) trebuie să returneze 5 și nu trebuie să arunce nicio eroare. Apelul vine primul; o eroare neașteptată ar încheia testul chiar acolo. Abia apoi este comparată valoarea.
Ieșire: program TypeScript și rezultatul capturat
import { test } from "node:test"
import assert from "node:assert/strict"
function safeDivide(a: number, b: number): number {
if (b === 0) {
throw new RangeError("nu se poate împărți la zero")
}
return a / b
}
test("safeDivide(10, 2) is 5", () => {
// O eroare neașteptată încheie testul chiar aici.
const got = safeDivide(10, 2)
assert.equal(got, 5, `safeDivide(10, 2) = ${got}; se aștepta 5`)
})
Calea greșită
Cealaltă jumătate a contractului: datele greșite trebuie să ducă la eșec. assert.throws primește o funcție mică ce face apelul, o rulează și eșuează dacă nu a fost aruncată nicio eroare.
Poți spune și ce anume trebuie aruncat. Dacă transmiți clasa erorii ca al doilea argument, testul eșuează atunci când iese un alt fel de eroare.
Datele greșite trebuie să arunce o eroare
Împărțirea la zero trebuie să eșueze. assert.throws apelează safeDivide(10, 0) și cere un RangeError. Dacă funcția ar returna în schimb un număr, testul ar eșua — a acceptat date pe care ar fi trebuit să le respingă.
Ieșire: program TypeScript și rezultatul capturat
import { test } from "node:test"
import assert from "node:assert/strict"
function safeDivide(a: number, b: number): number {
if (b === 0) {
throw new RangeError("nu se poate împărți la zero")
}
return a / b
}
test("safeDivide(10, 0) throws", () => {
assert.throws(() => safeDivide(10, 0), RangeError, "se aștepta o eroare la împărțirea la zero")
})
Un tabel cu wantErr
Ambele căi încap într-un singur test bazat pe tabel: dă fiecărui caz un câmp wantErr care spune dacă se așteaptă o eroare. Câmpul want este opțional, pentru că un caz care aruncă o eroare nu are nicio valoare de comparat.
Fiecare subtest se uită mai întâi la wantErr. Eșecurile așteptate sunt verificate cu assert.throws și se opresc acolo; celelalte cazuri compară valoarea ca de obicei.
Cazuri bune și rele într-un singur tabel
Patru cazuri: trei împărțiri obișnuite și o împărțire la zero cu wantErr: true. O singură buclă acoperă tot contractul funcției, iar toate cele patru subteste trec.
Ieșire: program TypeScript și rezultatul capturat
import { test } from "node:test"
import assert from "node:assert/strict"
function safeDivide(a: number, b: number): number {
if (b === 0) {
throw new RangeError("nu se poate împărți la zero")
}
return a / b
}
type Case = {
name: string
a: number
b: number
want?: number
wantErr: boolean
}
const cases: Case[] = [
{ name: "simple division", a: 10, b: 2, want: 5, wantErr: false },
{ name: "negative result", a: -9, b: 3, want: -3, wantErr: false },
{ name: "divide zero", a: 0, b: 5, want: 0, wantErr: false },
{ name: "divide by zero", a: 10, b: 0, wantErr: true }
]
test("safeDivide", async (t) => {
for (const c of cases) {
await t.test(c.name, () => {
if (c.wantErr) {
assert.throws(() => safeDivide(c.a, c.b), RangeError)
return
}
const got = safeDivide(c.a, c.b)
assert.equal(got, c.want, `safeDivide(${c.a}, ${c.b}) = ${got}; se aștepta ${c.want}`)
})
}
})