Test Runner

Vitest

Vitest ist der schnelle, Vite-native Test-Runner. Er nutzt deine Build-Konfiguration wieder, führt Tests parallel aus und bietet Jest-kompatible APIs mit erstklassigem TypeScript-Support.

intermediate13 min readUpdated 15. Sept. 2026
sum.test.ts
ts
// sum.test.ts
import { describe, it, expect } from "vitest";
import { sum } from "./sum";

describe("sum", () => {
  it("adds two numbers", () => {
    expect(sum(2, 3)).toBe(5);
  });

  it("handles negatives", () => {
    expect(sum(-1, -1)).toBe(-2);
  });
});
Basiert auf
Vite
API
Jest-kompatibel
Sprache
TypeScript native
Mocks
vi.fn, vi.mock
Watch-Modus
Sofortig, Vite HMR
Browser-Modus
Echtes Browser-Testing

Warum es wichtig ist

Warum Vitest gewinnt

Standardmäßig schnell

Tests laufen über die Transform-Pipeline von Vite in parallelen Workern, sodass das Feedback selbst bei großen Test-Suites nahezu sofort erfolgt.

Nutzt deine Konfiguration

Aliase, Plugins und TypeScript-Einstellungen stammen aus derselben Vite-Konfiguration, die deine App bereits nutzt – es gibt also nichts zu duplizieren.

Jest-kompatible API

describe, it, expect und die Mocking-Helfer spiegeln Jest wider, was die Migration und das Teilen von Wissen vereinfacht.

Das Gesamtbild

Die drei Kernideen hinter Vitest

Eine Vite-native Pipeline, eine Jest-kompatible API und parallele Worker, die den Feedback-Zyklus extrem schnell halten.

Der Runner

Ausführen

Findet Testdateien, führt sie in parallelen Workern aus und berichtet die Ergebnisse über ein klares, schnelles UI.

Die Transformation

Build

Nutzt Vite, um TypeScript, JSX und Aliase exakt so zu kompilieren, wie es deine App tut.

Assertions und Mocks

Verifizieren

expect, vi.fn und vi.mock decken Assertions, Spies und das Mocken von Modulen ab.

Vitest auf einen Blick

Das Herzstück von Vitest

describe und it

Gruppiere zusammengehörige Tests und benenne jeden nach dem Verhalten, das er verifiziert.

expect

Eine umfangreiche Matcher-API für Werte, Objekte, Fehler und asynchrone Ergebnisse.

vi.fn und vi.spyOn

Erstelle Mocks und Spies, um den zu testenden Code zu isolieren.

vi.mock

Ersetze ein gesamtes Modul durch einen Mock, wobei der Aufruf über die Imports gehoben (hoisted) wird.

Asynchrones Testen

Warte auf Promises und nutze expect.resolves oder expect.rejects.

Coverage und UI

Integriertes Coverage-Reporting und ein optionales Browser-UI.

Eine kurze Geschichte

Ein Test-Runner, gebaut für Vite

  1. 2021

    Vitest angekündigt

    Anthony Fu stellt einen Vite-nativen Test-Runner vor, der die bestehende Pipeline wiederverwendet.

    21
  2. 2022

    Grundstein für Vitest 1.0

    Schnelle Releases fügen Coverage, Browser-Modus und Jest-Kompatibilität hinzu.

    22
  3. 2024

    Vitest 1 und 2

    Eine stabile API, Workspace-Projekte und der Browser-Modus reifen aus.

    24
  4. Heute

    Der Standard für Vite

    Der empfohlene Test-Runner für Vite, Vue, Svelte, Solid und viele React-Setups.

    Heute

Der vollständige Leitfaden

Vitest: Alles was Sie wissen müssen

Was ist Vitest?

Vitest ist ein Test-Runner, der auf Vite basiert. Er nutzt deine bestehende Vite-Konfiguration – inklusive Aliases, Plugins sowie TypeScript- und JSX-Transformationen –, sodass die Tests dieselbe Pipeline durchlaufen wie deine Anwendung. Dieses gemeinsame Fundament ist der Grund, warum Vitest schnell startet und schnell bleibt.

Die API wird dir bekannt vorkommen, wenn du bereits Jest verwendet hast. describe, it, expect und die Mocking-Helper funktionieren auf die gleiche Weise. Was sich ändert, ist die Engine im Hintergrund: Vitest führt Tests in parallelen Workern aus, überwacht Dateien mithilfe des Modul-Graphen von Vite und bietet erstklassigen TypeScript-Support ohne zusätzliche Konfiguration.

Deinen ersten Test schreiben

Eine Testdatei importiert aus vitest und beschreibt das Verhalten, das sie verifiziert.

// sum.test.ts
import { describe, it, expect } from "vitest";
import { sum } from "./sum";

describe("sum", () => {
  it("adds two numbers", () => {
    expect(sum(2, 3)).toBe(5);
  });

  it("handles negatives", () => {
    expect(sum(-1, -1)).toBe(-2);
  });
});

Benenne Tests nach dem Verhalten, nicht nach der Funktion. Ein fehlgeschlagener Test mit dem Namen „addiert zwei Zahlen“ sagt dir genau, was kaputtgegangen ist; einer namens „sum test 1“ hingegen nicht. Gruppiere zusammengehörige Testfälle mit describe und nutze beforeEach sowie afterEach für das Setup und Cleanup.

Assertions

Vitest liefert eine umfangreiche Matcher-API mit, die sehr nah an der von Jest liegt.

// assertions.test.ts
expect(value).toBe(5);              // strict equality
expect(value).toEqual({ a: 1 });    // deep equality
expect(value).toBeTruthy();
expect(list).toHaveLength(3);
expect(list).toContain("a");
expect(fn).toThrow("invalid");
expect(value).toBeGreaterThan(3);

Verwenden Sie toEqual für Objekte und Arrays und toBe für Primitive und Referenzprüfungen. toMatchObject und toContainEqual sind nützlich, wenn Sie sich nur für einen Teil einer Struktur interessieren.

Mocks und Spies

Isolation ist zentral für Unit-Tests. Vitest bietet vi.fn für Mocks, vi.spyOn zum Wrappen bestehender Methoden und vi.mock zum Ersetzen ganzer Module.

// api.test.ts
import { vi, describe, it, expect } from "vitest";
import { fetchUser } from "./api";

vi.mock("./http", () => ({
  get: vi.fn().mockResolvedValue({ id: 1, name: "Ada" }),
}));

describe("fetchUser", () => {
  it("returns the user", async () => {
    await expect(fetchUser(1)).resolves.toEqual({ id: 1, name: "Ada" });
  });
});

vi.mock wird über die Imports gehoben (hoisted), sodass der Mock registriert wird, bevor das zu testende Modul ihn lädt. Wenn die Factory eine Variable benötigt, die in der Testdatei definiert ist, verwende vi.hoisted, damit der Wert existiert, bevor der Mock ausgeführt wird.

Asynchrones Testen

Warten Sie auf den Abschluss der Operation und prüfen Sie das Ergebnis. Vitest bietet die Helper resolves und rejects für Promises an.

// async.test.ts
it("rejects on failure", async () => {
  await expect(loadUser(-1)).rejects.toThrow("Invalid id");
});

Bevorzugen Sie diesen Stil gegenüber dem done-Callback. Wenn done vergessen wird, führt dies zu Timeouts, die schwer zu diagnostizieren sind, und nicht behandelte Rejections können in andere Tests überlaufen. Für Fake Timer ermöglichen vi.useFakeTimers() und vi.advanceTimersByTime() das deterministische Testen von Debounces und Intervallen.

Snapshots

Snapshots halten einen Wert fest und vergleichen ihn bei späteren Durchläufen. Sie sind nützlich für große, stabile Ausgaben wie serialisierte Daten oder gerendertes Markup, lassen sich jedoch leicht missbrauchen.

// snapshot.test.ts
it("matches the shape", () => {
  expect(createConfig({ debug: true })).toMatchSnapshot();
});

Ein Snapshot, der aktualisiert wird, ohne ihn zu prüfen, ist schlechter als gar kein Test. Nutzen Sie Snapshots für Datenstrukturen, bei denen ein vollständiger Vergleich unpraktisch ist, und bevorzugen Sie explizite Assertions, wenn Sie wissen, worauf es ankommt. toMatchInlineSnapshot hält den erwarteten Wert direkt in der Testdatei, was Code-Reviews sinnvoll macht.

Konfiguration

Vitest liest entweder einen test-Block aus deiner Vite-Konfiguration oder eine dedizierte vitest.config.ts aus.

// vitest.config.ts
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    environment: "jsdom",
    globals: true,
    coverage: {
      provider: "v8",
      reporter: ["text", "html"],
      thresholds: { lines: 80 },
    },
  },
});

Mit der Option environment wählst du zwischen node, jsdom, happy-dom oder einem Browser. Für Komponententests sind jsdom oder happy-dom üblich; für reine Logik empfiehlt sich die schnelle node-Umgebung. Coverage-Thresholds verwandeln ein Coverage-Ziel in eine verbindliche Regel.

Vitest und die Testpyramide

Vitest bildet die Schicht für Unit- und Integrationstests. Kombiniere es mit einer Component-Testing-Library wie Testing Library für das UI-Verhalten und mit einem End-to-End-Tool wie Playwright für vollständige User-Flows. Zusammen decken sie die Pyramide ab: viele schnelle Unit-Tests, weniger Integrationstests und eine Handvoll End-to-End-Tests.

Best Practices

  • Testen Sie das Verhalten, nicht die Implementierungsdetails.
  • Konzentrieren Sie jeden Test auf genau ein Verhalten.
  • Nutzen Sie beforeEach für das gemeinsame Setup und bereinigen Sie Mocks mit vi.clearAllMocks.
  • Bevorzugen Sie resolves und rejects gegenüber done-Callbacks.
  • Mocken Sie an den Grenzen (Netzwerk, Zeit, Zufall), nicht jeden internen Aufruf.
  • Verwenden Sie Coverage-Thresholds, um stille Regressionen zu vermeiden.
  • Führen Sie die Tests während der Entwicklung im Watch-Mode und in der CI bei jedem Push aus.

Häufige Fehler

  • Assertions auf internen Zuständen oder privaten Methoden statt auf beobachtbarem Verhalten.
  • Aktualisieren von Snapshots, ohne den Diff zu prüfen.
  • Vergessen, Mocks zwischen den Tests zu leeren, was zu State-Leaks führt.
  • Verwendung von echten Timern, wodurch Tests langsam und instabil (flaky) werden.
  • Übermäßiges Mocking, bis der Test nur noch die Mocks selbst verifiziert.
  • Testen desselben Verhaltens auf jeder Ebene der Testpyramide.

Wie geht es weiter?

Vitest ist der schnellste Weg, um mit dem Testen eines Vite-Projekts zu beginnen. Vergleiche es mit dem klassischen Jest, ergänze Testing Library für Komponenten sowie Playwright für End-to-End-Flows und nutze Vite, um die Konfiguration gemeinsam zu verwenden. Schreibe anschließend einige Tests für deinen bestehenden Code und erlebe, wie Refactorings sicher werden.

Asynchronen Code testen

Warte auf das Promise und prüfe das Ergebnis. Der done-Callback wird leicht vergessen und führt zu verwirrenden Timeouts.

Bevorzugt
it("loads the user", async () => {
  await expect(getUser(1)).resolves.toEqual({
    id: 1,
    name: "Ada",
  });
});
Vermeiden
it("loads the user", (done) => {
  getUser(1).then((user) => {
    expect(user.name).toBe("Ada");
    done();
  });
});

Ein Modul mocken

vi.mock wird über die Imports gehoben, sodass das Modul ersetzt wird, bevor der zu testende Code es lädt.

Bevorzugt
import { vi } from "vitest";

vi.mock("./api", () => ({
  fetchUser: vi.fn().mockResolvedValue({
    id: 1,
  }),
}));
Vermeiden
import * as api from "./api";
// reassigning after import
// is brittle and often fails
api.fetchUser = async () => ({ id: 1 });

Häufig gestellte Fragen

Häufig gestellte Fragen

Keep learning

Related topics from the roadmap.

$ Lernen Sie jetzt

Bereit, Vitest zu lernen?

Unser interaktives Tutorial führt Sie Schritt für Schritt durch Vitest — mit Quizzen und echtem Code, den Sie im Browser ausführen können.