Erste Schritte mit Front-End-Vue-Unit-Tests

Erste Schritte mit Front-End-Vue-Unit-Tests

1. Warum brauchen wir Unit-Tests?

Mithilfe von Unit-Tests wird die Funktionalität eines Moduls in einem Projekt getestet, beispielsweise einer Funktion, Klasse, Komponente usw. Die Funktionen des Unit-Tests sind wie folgt:

  • Korrektheit: Sie können die Korrektheit des Codes überprüfen und detailliertere Vorbereitungen treffen, bevor Sie online gehen.
  • Automatisierung: Testfälle können in die Codeversionsverwaltung integriert werden, um Unit-Tests automatisch auszuführen und jedes Mal manuelle Vorgänge zu vermeiden;
  • Erklärend: Es kann anderen Entwicklern Verweise auf die Dokumentation des zu testenden Moduls liefern. Das Lesen der Testfälle kann vollständiger sein als die Dokumentation.
  • Entwicklung vorantreiben und Design leiten: Vorab geschriebene Unit-Tests können den API-Entwurf der Entwicklung leiten und auch Probleme im Design im Voraus erkennen.
  • Refactoring sicherstellen: Testfälle können mehrfach überprüft werden, was bei erforderlichen Regressionstests viel Zeit sparen kann.

2. So schreiben Sie Unit-Tests

Testprinzipien

  • Berücksichtigen Sie beim Testen von Code nur den Test und nicht die interne Implementierung.
  • Die Daten sollten die Realität so gut wie möglich simulieren. Je näher an der Realität, desto besser
  • Berücksichtigen Sie die Randbedingungen der Daten
  • Konzentrieren Sie sich auf das Testen von Schlüssel-, Komplex- und Kerncodes
  • Die Kombination von Tests und funktionaler Entwicklung ist für Design und Code-Refactoring von Vorteil

Schritte zum Schreiben

  • Vorbereitungsphase: Parameter konstruieren, Spion erstellen usw.
  • Ausführungsphase: Ausführen des getesteten Codes mit konstruierten Parametern
  • Assert-Phase: Vergleichen Sie die tatsächlichen Ergebnisse mit den erwarteten Ergebnissen, um festzustellen, ob der Test normal ist
  • Bereinigungsphase: Bereinigen Sie die Auswirkungen der Vorbereitungsphase auf die externe Umgebung, entfernen Sie den in der Vorbereitungsphase erstellten Spion usw.

3. Testwerkzeuge

Unit-Test-Tools können in drei Kategorien unterteilt werden:

  • Test Runner: kann verschiedene Browserumgebungen simulieren, Test-Frameworks und Assertion-Bibliotheken wie Karma anpassen.
  • Testframework: Bietet Funktionsmodule für Unittests. Gängige Frameworks sind Jest, Mocha, Jasmine und QUnit.
  • Werkzeugbibliotheken: Assertion-Bibliotheken wie assert, should.js, expect.js, chai.js, Enzyme-Rendering-Bibliothek, Istanbul-Coverage-Berechnung.

Hier verwenden wir Jest als Beispiel. Jest ist umfassend, integriert verschiedene Tools und lässt sich einfach konfigurieren oder sogar direkt ohne Konfiguration verwenden.

4. Erste Schritte mit Jest

Die Beschreibung auf der offiziellen Website von Jest lautet wie folgt:

Jest ist ein wunderbares JavaScript-Test-Framework mit Fokus auf Einfachheit.

Installieren

yarn add --dev Scherz
# oder
# npm install -D Scherz

Einfaches Beispiel

Ausgehend vom Beispiel auf der offiziellen Website testen wir eine Funktion, die zwei Zahlen addiert, und erstellen eine Datei sum.js:

Funktion Summe(a, b) {
  gib a + b zurück;
}
module.exporte = Summe;

Erstellen Sie dann die Datei sum.test.js:

const Summe = erfordern('./Summe');

test('addiert 1 + 2 ergibt 3', () => {
  erwarte(Summe(1, 2)).soll(3);
});

Fügen Sie in package.json eine Testaufgabe hinzu:
{
  "Skripte": {
    "Test": "Scherz"
  }
}

Wenn Sie schließlich yarn test oder npm run test ausführen, druckt Jest die folgende Meldung:

PASS ./sum.test.js
✓ addiert 1 + 2 ergibt 3 (5 ms)

An dieser Stelle ist ein grundlegender Unit-Test abgeschlossen.

Hinweis: Jest verwendet JSDOM, um einen echten Browser in der virtuellen Node-Browserumgebung zu simulieren. Da DOM mit js simuliert wird, kann Jest keine Stile testen. Der Jest-Testrunner richtet JSDOM automatisch ein.

Scherz-Cli

Sie können Jest direkt von der Befehlszeile aus ausführen (vorausgesetzt, Jest befindet sich bereits in Ihrem PATH, z. B. über yarn global add jest oder npm install jest --global) und verschiedene nützliche Konfigurationsoptionen dafür angeben. wie:

Scherz mein-Test --notify --config=config.json

Der Jest-Befehl hat die folgenden allgemeinen Parameter:

  • --coverage bedeutet, dass die Unit-Test-Abdeckung ausgegeben wird. Die Abdeckungsdatei befindet sich standardmäßig in tests/unit/coverage/lcov-report/index.html.
  • --watch-Überwachungsmodus, jede Änderung an Dateien, die mit dem Testfall in Zusammenhang stehen, löst den Komponententest erneut aus.

Weitere Optionen finden Sie unter Jest CLI-Optionen.

Verwenden der Konfigurationsdatei

Verwenden Sie den Befehl „jest“, um eine Konfigurationsdatei zu generieren:

Scherz --init

Sie haben mehrere Optionen zur Auswahl:

√ Möchten Sie Typescript für die Konfigurationsdatei verwenden? ... nein
√ Wählen Sie die Testumgebung, die zum Testen verwendet werden soll » jsdom (browserähnlich)
√ Möchten Sie, dass Jest Berichterstattungsberichte hinzufügt? ... ja
√ Welcher Anbieter sollte zum Instrumentieren des Codes für die Abdeckung verwendet werden? » babel
√ Mock-Aufrufe und Instanzen zwischen jedem Test automatisch löschen? ... ja

Beispielkonfigurationsdatei (basiert nicht auf den obigen Auswahlen):

// jest.config.js
const Pfad = require('Pfad')

modul.exporte = {
    Vorgabe: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
    rootDir: Pfad.resolve(__dirname, './'),
    Abdeckungsverzeichnis: '<Stammverzeichnis>/tests/unit/coverage',
    collectCoverageFrom: [
        „Quelle/*.{js,ts,vue}“,
        „src/direktiven/*.{js,ts,vue}“,
        „src/filters/*.{js,ts,vue}“,
        „src/helper/*.{js,ts,vue}“,
        „Quelle/Ansichten/**/*.{js,ts,vue}“,
        „Quelle/Dienste/*.{js,ts,vue}“
    ]
}

Babel verwenden

yarn add --dev babel-jest @babel/core @babel/preset-env

Sie können im Stammverzeichnis Ihres Projekts eine Datei babel.config.js erstellen, um Babel kompatibel mit Ihrer aktuellen Node-Version zu konfigurieren:

// babel.config.js
modul.exporte = {
  Voreinstellungen: [['@babel/preset-env', {Ziele: {Knoten: 'current'}}]],
};

Verwenden von Jest in vue-cli

Installieren Sie das Plugin @vue/cli-plugin-unit-jest in Ihrem Projekt, um Jest in vue-cli zu verwenden:

vue add unit-scherz
# oder
# Garn hinzufügen -D @vue/cli-plugin-unit-jest @types/jest
"Skripte": {
    „Test:Einheit“: „vue-cli-service Test:Einheit --Abdeckung“
},

@vue/cli-plugin-unit-jest fügt den Befehl test:unit in den vue-cli-service ein und erkennt standardmäßig die folgenden Dateien: <rootDir>/(tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)) zum Ausführen von Unit-Tests, d. h. Dateien mit der Endung .spec.(js|jsx|ts|tsx) im Verzeichnis tests/unit und alle js(x)/ts(x)-Dateien im Verzeichnis mit dem Namen __tests__.

Häufige Beispiele

Beurteilen Sie, ob der Wert gleich ist

toBe() prüft, ob zwei primitive Typen genau übereinstimmen:

test('zwei plus zwei ist vier', () => {
  erwarte(2 + 2).zuSein(4);
});

toEqual() prüft, ob Objekte gleich sind:

test('Objektzuweisung', () => {
  const Daten = {eins: 1};
  Daten['zwei'] = 2;
  expect(data).toEqual({eins: 1, zwei: 2});
});

Auf falsche Werte prüfen

  • toBeNull stimmt nur mit null überein
  • toBeUndefined stimmt nur mit undefined überein
  • toBeDefined ist das Gegenteil von toBeUndefined
  • toBeTruthy entspricht jeder if-Anweisung, die wahr ist
  • toBeFalsy stimmt mit jeder if-Anweisung überein, die falsch ist.

Beispiel:

Prüfung('null', () => {
  const n = null;
  erwarte(n).toBeNull();
  erwarten(n).toBeDefined();
  erwarte(n).nicht.zuBeUndefined();
  erwarte(n).nicht.die Wahrheit zu Sein();
  erwarte(n).toBeFalsy();
});

test('null', () => {
  konstant z = 0;
  expect(z).not.toBeNull();
  Erwarte(z).toBeDefined();
  expect(z).not.toBeUndefined();
  erwarte(z).nicht.zuBeWahrhaftig();
  expect(z).toBeFalsy();
});

Zahlenvergleich

test('zwei plus zwei', () => {
  konstanter Wert = 2 + 2;
  erwarte(Wert).toBeGreaterThan(3);
  erwarte(Wert).solltegrößeralsodergleich(3,5) sein;
  erwarte(Wert).toBeLessThan(5);
  erwarte(Wert).sollte kleiner oder gleich sein(4,5);

  // toBe und toEqual sind für Zahlen gleichwertig
  erwarte(Wert).soll(4);
  erwarte(Wert).toEqual(4);
});

Um Gleitkommazahlen auf Gleichheit zu vergleichen, verwenden Sie toBeCloseTo statt toEqual, da der Test nicht von einem winzigen Rundungsfehler abhängig sein soll.

test('Zwei Gleitkommazahlen hinzufügen', () => {
  konstanter Wert = 0,1 + 0,2;
  //expect(value).toBe(0.3); Dies wird einen Fehler werfen, weil Gleitkommazahlen Rundungsfehler haben expect(value).toBeCloseTo(0.3); // Das funktioniert });

Stringvergleich

Mit regulären Ausdrücken können Sie Folgendes überprüfen:

test('Es gibt kein Ich im Team', () => {
  erwarte('team').nicht.toMatch(/I/);
});

test('aber in Christoph steckt ein "Stopp"', () => {
  expect('Christoph').toMatch(/stop/);
});

Arrays und arrayähnliche

Mit toContain können Sie prüfen, ob ein Array oder Iterable ein bestimmtes Element enthält:

const Einkaufsliste = [
  'Windeln',
  'Kleenex',
  'Müllsäcke',
  'Papiertücher',
  'Milch',
];

test('auf der Einkaufsliste steht Milch', () => {
  erwarte(Einkaufsliste).enthält('Milch');
  erwarte(neues Set(Einkaufsliste)).enthält('Milch');
});

abnormal

Damit lässt sich auch prüfen, ob eine Funktion eine Ausnahme auslöst:

Funktion kompiliereAndroidCode() {
  throw new Error('Sie verwenden das falsche JDK');
}

test('Android kompilieren läuft wie erwartet', () => {
  expect(() => kompiliereAndroidCode()).toThrow();
  expect(() => kompiliereAndroidCode()).toThrow(Fehler);

  // Sie können auch die genaue Fehlermeldung oder einen regulären Ausdruck verwenden
  expect(() => compileAndroidCode()).toThrow('Sie verwenden das falsche JDK');
  expect(() => kompiliereAndroidCode()).toThrow(/JDK/);
});

Weitere Informationen zur Verwendung finden Sie in der API-Dokumentation.

Führen Sie nur den aktuellen Test aus

Mit der Methode only() können Sie angeben, dass nur dieser Test ausgeführt wird. So werden unnötige wiederholte Tests vermieden:

test.only('es regnet', () => {
  erwarte(ZollRegen()).sollgrößerseinals(0);
});

test('es schneit nicht', () => {
  erwarte(ZollSchnee()).soll(0);
});

Testen von asynchronem Code

Callback-Funktion

Angenommen, Sie haben eine Funktion „fetchData(callback)“, die einige Daten abruft und „callback(data)“ aufruft, wenn sie fertig ist. Sie erwarten, dass die zurückgegebenen Daten die Zeichenfolge „Erdnussbutter“ sind:

test('die Daten sind Erdnussbutter', fertig => {
  Funktion Rückruf(Daten) {
    versuchen {
      expect(data).toBe('Erdnussbutter');
      Erledigt();
    } Fehler abfangen {
      fertig (Fehler);
    }
  }

  fetchData(Rückruf);
});

Done() wird verwendet, um den Abschluss des Tests zu markieren. Ohne done() wird unser Unit-Test beendet, nachdem der Test abgeschlossen ist, was nicht unseren Erwartungen entspricht, da der Rückruf nicht aufgerufen wurde und der Unit-Test nicht abgeschlossen wurde. Wenn die Funktion done() nie aufgerufen wird, wird ein Timeout-Fehler gemeldet.

Wenn die Ausführung von expect fehlschlägt, wird ein Fehler ausgegeben und das folgende done() wird nicht ausgeführt. Wenn wir wissen möchten, warum der Testfall fehlgeschlagen ist, müssen wir das Erwartete in das Versuchen einfügen und den Fehler im Fangen an die Fertigfunktion übergeben. Andernfalls zeigt die Konsole einen Timeout-Fehler an und der Wert, den wir in expect(data) erhalten haben, wird nicht angezeigt.

Versprechen

Wir verwenden immer noch das obige Beispiel:

test('die Daten sind Erdnussbutter', () => {
  returniere fetchData().then(data => {
    expect(data).toBe('Erdnussbutter');
  });
});

Vergessen Sie nicht, das Ergebnis zurückzugeben, damit der Test und die Funktion gleichzeitig abgeschlossen werden.
Wenn Sie erwarten, dass Promise abgelehnt wird, verwenden Sie die Catch-Methode:

test('der Abruf schlägt mit einem Fehler fehl', () => {
  erwarten.Assertions(1);
  returniere fetchData().catch(e => expect(e).toMatch('error'));
});

Sie können auch die Matcher „Resolves“ und „Rejects“ verwenden:

test('die Daten sind Erdnussbutter', () => {
  returniere expect(fetchData()).resolves.toBe('Erdnussbutter');
});

test('der Abruf schlägt mit einem Fehler fehl', () => {
  gibt expect(fetchData()).rejects.toMatch('Fehler') zurück;
});

Asynchron/Warten

test('die Daten sind Erdnussbutter', async () => {
  const data = warte auf fetchData();
  expect(data).toBe('Erdnussbutter');
});

test('der Abruf schlägt mit einem Fehler fehl', async () => {
  erwarten.Assertions(1);
  versuchen {
    warte auf fetchData();
  } fangen (e) {
    erwarten(e).toMatch('Fehler');
  }
});

async/await kann auch in Verbindung mit resolves()/rejects() verwendet werden:

test('die Daten sind Erdnussbutter', async () => {
  warte auf expect(fetchData()).resolves.toBe('Erdnussbutter');
});

test('der Abruf schlägt mit einem Fehler fehl', async () => {
  warte auf expect(fetchData()).rejects.toMatch('error');
});

Installation und Entfernung

Vorher-Nachher-Test

In manchen Fällen müssen wir vor dem Testbeginn einige Vorbereitungen treffen und nach Abschluss des Tests einige Bereinigungen durchführen. Sie können beforeEach und afterEach verwenden.
Beispielsweise müssen wir vor jedem Test einige Stadtdaten initialisieren und nach dem Test bereinigen:

vorJedem(() => {
  initialisierenCityDatabase();
});

nachJedem(() => {
  : ClearCityDatabase();
});

test('Stadtdatenbank hat Wien', () => {
  expect(isCity('Wien')).toBeTruthy();
});

test('Städtedatenbank enthält San Juan', () => {
  erwarte(istStadt('San Juan')).toBeTruthy();
});

Ähnliche Methoden sind beforeAll und afterAll, die einmal vor und nach dem Start und Ende der aktuellen Spezifikationstestdatei ausgeführt werden.

Testfallgruppierung

Standardmäßig werden auf jeden Test in der Datei Vorher- und Nachher-Blöcke angewendet. Darüber hinaus können Tests mithilfe von Beschreibungsblöcken gruppiert werden. Wenn sich die Blöcke „Vorher“ und „Nachher“ innerhalb eines Beschreibungsblocks befinden, gelten sie nur für die Tests innerhalb dieses Beschreibungsblocks.

// Gilt für alle Tests in dieser Datei
vorJedem(() => {
  gibt initializeCityDatabase() zurück;
});

test('Stadtdatenbank hat Wien', () => {
  expect(isCity('Wien')).toBeTruthy();
});

test('Städtedatenbank enthält San Juan', () => {
  erwarte(istStadt('San Juan')).toBeTruthy();
});

describe('Städte Nahrungsmitteln zuordnen', () => {
  // Gilt nur für Tests in diesem Beschreibungsblock
  vorJedem(() => {
    returniere initializeFoodDatabase();
  });

  test('Wiener <3 Würstchen', () => {
    expect(isValidCityFoodPair('Wien', 'Wiener Würstchen')).toBe(true);
  });

  test('San Juan <3 Kochbananen', () => {
    erwarte(isValidCityFoodPair('San Juan', 'Mofongo')).soll(wahr) sein;
  });
});

Ausführungsreihenfolge

Da „describe“ zur Gruppierung verwendet wird, gibt es verschachtelte Bereiche. Die Ausführungsreihenfolge jedes Lebenszyklus ist wie folgt:

  • Das „Vorher“ des äußeren Bereichs wird vor dem inneren Bereich ausgeführt, während das „Nachher“ das Gegenteil ist.
  • Auf derselben Ebene wird beforeAll vor beforeEach ausgeführt und after ist das Gegenteil der Fall.
vorAllem(() => console.log('1 - vorAllem'));
nachAllem(() => console.log('1 - nachAllem'));
vorJedem(() => console.log('1 - vorJedem'));
nachJedem(() => console.log('1 - nachJedem'));
test('', () => console.log('1 - test'));
beschreiben('Bereichsbezogener / verschachtelter Block', () => {
  beforeAll(() => console.log('2 - beforeAll'));
  nachAllem(() => console.log('2 - nachAllem'));
  vorJedem(() => console.log('2 - vorJedem'));
  nachJedem(() => console.log('2 - nachJedem'));
  test('', () => console.log('2 - test'));
});

// 1 - vorAllem
// 1 - vor jedem
// 1 - Prüfung
// 1 - nachJedem
// 2 - vorAllem
// 1 - vor jedem
// 2 - vorJedem
// 2 - Prüfung
// 2 - nachJedem
// 1 - nachJedem
// 2 - nach allem
// 1 - nach allem

Mock-Funktion

Mit jest.fn() kann eine Mock-Funktion generiert werden. Jest kann den Aufruf, this, den Rückgabewert usw. dieser Funktion erfassen, was beim Testen von Callback-Funktionen sehr nützlich ist.

Testen von Mock-ups

Angenommen, wir möchten die interne Implementierung der Funktion forEach testen, die für jedes Element im übergebenen Array einmal eine Rückruffunktion aufruft.

Funktion fürJedes(Elemente, Rückruf) {
  für (let index = 0; index < items.length; index++) {
    Rückruf(Elemente[Index]);
  }
}

Um diese Funktion zu testen, können wir eine Mock-Funktion verwenden und dann den Status der Mock-Funktion überprüfen, um sicherzustellen, dass die Rückruffunktion wie erwartet aufgerufen wird.

const mockCallback = jest.fn(x => 42 + x);
fürJedes([0, 1], mockCallback);

// Diese Mock-Funktion wird zweimal aufgerufen expect(mockCallback.mock.calls.length).toBe(2);

// Der erste Parameter beim ersten Aufruf der Funktion ist 0
erwarten(mockCallback.mock.calls[0][0]).toBe(0);

// Der erste Parameter beim zweiten Aufruf der Funktion ist 1
erwarten(mockCallback.mock.calls[1][0]).toBe(1);

// Der Rückgabewert des ersten Funktionsaufrufs ist 42
erwarte(mockCallback.mock.results[0].value).toBe(42);

Scheinrückgabewert

Mock-Funktionen können auch verwendet werden, um während des Tests Testwerte in den Code einzufügen:

const myMock = jest.fn();
console.log(myMock());
// > undefiniert

myMock.mockReturnValueOnce(10).mockReturnValueOnce('x').mockReturnValue(true);

console.log(meinMock(), meinMock(), meinMock(), meinMock());
// > 10, 'x', wahr, wahr

Rückgabe der Simulationsschnittstelle

Angenommen, es gibt eine Klasse, die Benutzer von einer API abruft. Diese Klasse verwendet Axios, um die API aufzurufen und gibt Daten zurück, die die Attribute aller Benutzer enthalten:

// Benutzer.js
importiere Axios von „Axios“;

Klasse Benutzer {
  statisch alle() {
    return axios.get('/users.json').then(resp => resp.data);
  }
}

Standardbenutzer exportieren;

Um diese Methode nun zu testen, ohne die API tatsächlich aufzurufen (was den Test langsam und fehleranfällig machen würde), können wir die Funktion jest.mock(...) verwenden, um das Axios-Modul automatisch zu simulieren. Sobald das Modul simuliert ist, können wir .get einen mockResolvedValue bereitstellen, der gefälschte Daten zum Testen zurückgibt.

// Benutzer.test.js
importiere Axios von „Axios“;
Benutzer aus „./users“ importieren;

Scherz.mock('axios');

test('sollte Benutzer abrufen', () => {
  const Benutzer = [{name: 'Bob'}];
  const resp = {Daten: Benutzer};
  axios.get.mockResolvedValue(resp);

  // oder Sie können je nach Anwendungsfall Folgendes verwenden:
  // axios.get.mockImplementation(() => Promise.resolve(bzw.))

  gibt Benutzer zurück.alle().dann(Daten => erwarten(Daten).toEqual(Benutzer));
});

Mock-Funktionsmatcher

Mit der Mock-Funktion können Sie der Funktion einige benutzerdefinierte Matcher hinzufügen:

// Die Mock-Funktion wurde mindestens einmal aufgerufen
erwarten(mockFunc).toHaveBeenCalled();

// Die Mock-Funktion wurde mindestens einmal mit den angegebenen Argumenten aufgerufen
erwarte(mockFunc).toHaveBeenCalledWith(arg1, arg2);

// Der letzte Aufruf der Mock-Funktion wurde mit den angegebenen Argumenten ausgeführt
erwarte(mockFunc).toHaveBeenLastCalledWith(arg1, arg2);

// Alle Aufrufe und der Name des Mocks werden als Snapshot geschrieben
erwarten(mockFunc).toMatchSnapshot();

Sie können es auch selbst über den nativen Matcher simulieren. Der folgende Code entspricht dem obigen:
// Die Mock-Funktion wurde mindestens einmal aufgerufen
erwarte(mockFunc.mock.calls.length).toBeGreaterThan(0);

// Die Mock-Funktion wurde mindestens einmal mit den angegebenen Argumenten aufgerufen
erwarte(mockFunc.mock.calls).toContainEqual([arg1, arg2]);

// Der letzte Aufruf der Mock-Funktion wurde mit den angegebenen Argumenten ausgeführt
erwarten(mockFunc.mock.calls[mockFunc.mock.calls.length - 1]).toEqual([
  arg1,
  arg2,
]);

// Das erste Argument des letzten Aufrufs der Mock-Funktion war „42“
// (beachten Sie, dass es für diese spezielle Art einer Behauptung keinen Sugar-Helfer gibt)
erwarten(mockFunc.mock.calls[mockFunc.mock.calls.length - 1][0]).toBe(42);

// Ein Snapshot überprüft, ob ein Mock gleich oft aufgerufen wurde,
// in der gleichen Reihenfolge, mit den gleichen Argumenten.
erwarten(mockFunc.mock.calls).toEqual([[arg1, arg2]]);
expect(mockFunc.getMockName()).toBe('ein Scheinname');

Vue Test Utilities

Die offizielle Website stellt Vue Test Utils wie folgt vor:

Vue Test Utils ist die offizielle Unit-Test-Dienstprogrammbibliothek für Vue.js.

Die folgenden Beispiele basieren auf dem Vue-CLI-Gerüst, einschließlich Webpack/Babel/Vue-Loader

Testen von Einzeldateikomponenten

Die Einzeldateikomponenten von Vue müssen vorkompiliert werden, bevor sie in Node oder im Browser ausgeführt werden können. Wir empfehlen, dies auf zwei Arten zu erreichen: über einen Jest-Precompiler oder direkt mit webpack. Hier wählen wir den Jest-Ansatz.

Garn hinzufügen -D Scherz @vue/test-utils vue-jest

vue-jest unterstützt derzeit nicht alle Funktionen von vue-loader, wie etwa benutzerdefinierte Blöcke und das Laden von Stilen. Darüber hinaus werden webpack-spezifische Funktionen wie die Codetrennung nicht unterstützt. Um diese nicht unterstützten Funktionen zu verwenden, müssen Sie zum Ausführen Ihrer Tests Mocha statt Jest und zum Kompilieren Ihrer Komponenten Webpack verwenden.

Umgang mit Webpack-Aliasen

Standardmäßig verwendet vue-cli @ als Alias ​​für /src und Jest muss es auch separat konfigurieren:

// jest.config.js

modul.exporte = {
    ModulNameMapper: {
        '^@/(.*)$': '<Stammverzeichnis>/src/$1'
    }
}

Montagekomponenten

Die gemountete Komponente wird an einen Wrapper zurückgegeben, der viele praktische Methoden zum Kapseln, Durchlaufen und Abfragen der darin enthaltenen Vue-Komponenteninstanz bereitstellt.

//test.js

// Importieren Sie die Methode „mount()“ aus der Test-Utils-Bibliothek // und die Komponente, die Sie testen möchten. Importieren Sie { mount } von „@vue/test-utils“.
Zähler aus './counter' importieren

// Jetzt mounten wir die Komponente und wir erhalten den Wrapper const wrapper = mount(Counter)

// Sie können auf die eigentliche Vue-Instanz über „wrapper.vm“ zugreifen const vm = wrapper.vm

// Loggen Sie es in der Konsole ein, um den Wrapper im Detail zu überprüfen // Unsere Erkundung der Vue Test Utils beginnt hier console.log(wrapper)

Beim Mounten können Sie verschiedene Eigenschaften der Komponente festlegen:

const Wrapper = Mount (Zähler, {
    lokalesVue,
    Daten() {
        zurückkehren {
            Leiste: 'meine-Überschreibung'
        }
    },
    EigenschaftenDaten: {
        Nachricht: 'abc'
    },
    parentComponent: Foo, // Die übergeordnete Komponente angeben provide: {
        foo() {
            gibt „fooValue“ zurück
        }
    }
})

Testen Sie das von der Komponente gerenderte HTML

Verwenden Sie die zugehörigen Methoden des Wrappers, um zu bestimmen, ob das vom Bestandteil gerenderte HTML den Erwartungen entspricht.

importiere { mount } von '@vue/test-utils'
Zähler aus './counter' importieren

beschreiben('Zähler', () => {
  // Jetzt mounten wir die Komponente und wir erhalten den Wrapper const wrapper = mount(Counter)

  test('gibt das richtige Markup wieder', () => {
    erwarten(wrapper.html()).toContain('<span class="count">0</span>')
  })

  // Auch praktisch um zu prüfen, ob Elemente vorhanden sind test('has a button', () => {
    Erwarte (Wrapper.enthält ('Schaltfläche')).Soll (wahr) sein.
  })
})

Simulieren Sie Benutzeraktionen

Wenn der Benutzer auf die Schaltfläche klickt, sollte unser Zähler hochzählen. Um dieses Verhalten zu simulieren, müssen wir zunächst die Schaltfläche über wrapper.find() lokalisieren, wodurch ein Wrapper für das Schaltflächenelement zurückgegeben wird. Wir können dann einen Klick simulieren, indem wir .trigger() im Button-Wrapper aufrufen.

it('Klick auf die Schaltfläche sollte den Zähler erhöhen', () => {
  erwarte(wrapper.vm.count).toBe(0)
  const button = wrapper.find('Schaltfläche')
  button.trigger('klicken')
  erwarte(wrapper.vm.count).toBe(1)
})

Um zu testen, ob der Text im Zähler aktualisiert wurde, müssen wir etwas über nextTick wissen. Alle Änderungen, die zu einer Manipulation des DOM führen, sollten vor der Assertion auf nextTick warten.

it('Schaltflächenklick sollte den Zähltext erhöhen', async () => {
  erwarten(wrapper.text()).toContain('0')
  const button = wrapper.find('Schaltfläche')
  warte auf button.trigger('klicken')
  erwarten(wrapper.text()).toContain('1')
})

Komponentenereignisse

Jeder bereitgestellte Wrapper protokolliert automatisch alle von der dahinter liegenden Vue-Instanz ausgelösten Ereignisse. Sie können diese Ereignisdatensätze mit der Methode wrapper.emitted() abrufen.

wrapper.vm.$emit('foo')
wrapper.vm.$emit('foo', 123)

/*
`wrapper.emitted()` gibt das folgende Objekt zurück:
{
  foo: [[], [123]]
}
*/

Sie können dann auf Grundlage dieser Daten Aussagen treffen:

// Stellen Sie sicher, dass das Ereignis ausgegeben wurde expect(wrapper.emitted().foo).toBeTruthy()

// Anzahl der Ereignisse bestätigen expect(wrapper.emitted().foo.length).toBe(2)

// Stellen Sie sicher, dass das Ereignis gültige Daten enthält expect(wrapper.emitted().foo[1]).toEqual([123])

Sie können Ereignisse auch auf Unterkomponenten auslösen:

importiere { mount } von '@vue/test-utils'
importiere ParentComponent aus '@/components/ParentComponent'
Importiere ChildComponent aus '@/components/ChildComponent'

beschreiben('ÜbergeordneteKomponente', () => {
  test("zeigt 'Emitted!' an, wenn ein benutzerdefiniertes Ereignis ausgegeben wird", () => {
    const Wrapper = Mount (übergeordnete Komponente).
    wrapper.find(Untergeordnete Komponente).vm.$emit('benutzerdefiniert')
    expect(wrapper.html()).toContain('Ausgegeben!')
  })
})

Bauteildaten

Sie können setData() oder setProps verwenden, um die Statusdaten der Komponente festzulegen:

it('manipuliert den Zustand', async () => {
  warte auf Wrapper.setData({ Anzahl: 10 })

  warte auf Wrapper.setProps({ foo: 'bar' })
})

Vue-Instanzmethode simulieren

Da setMethods() von Vue Test Utils bald veraltet ist, wird empfohlen, die Methode jest.spyOn() zu verwenden, um Vue-Instanzmethoden zu simulieren:

importiere MyComponent aus '@/components/MyComponent.vue'

beschreiben('MeineKomponente', () => {
  es('Klick bewirkt etwas', async () => {
    const mockMethod = jest.spyOn(MyComponent.methods, 'doSomething')
    warte auf flacherMount(MeineKomponente).find('Schaltfläche').trigger('Klick')
    erwarten(mockMethod).toHaveBeenCalled()
  })
})

Globale Plugins

Wenn Sie ein globales Plugin installieren müssen, das von allen Tests verwendet wird, können Sie setupFiles verwenden und zuerst die Setup-Datei in jest.config.js angeben:

// jest.config.js
modul.exporte = {
    Setup-Dateien: ['<Stammverzeichnis>/tests/unit/setup.js']
}

Verwenden Sie es dann in setup.js:

// setup.js
Vue von „vue“ importieren

// Die folgenden global registrierten Plugins funktionieren nicht in Jest und es muss localVue verwendet werden
importiere ElementUI von „element-ui“
Importiere VueClipboard aus „vue-clipboard2“

Vue.use(ElementUI)
Vue.use(VueClipboard)

Vue.config.productionTip = falsch

Wenn Sie in einigen Tests nur ein globales Plug-In installieren möchten, können Sie localVue verwenden, wodurch eine temporäre Vue-Instanz erstellt wird:

importiere { createLocalVue, mount } von '@vue/test-utils'

//Erstellen Sie einen erweiterten „Vue“-Konstruktor const localVue = createLocalVue()

//Installiere das Plugin normal localVue.use(MyPlugin)

// Übergeben Sie „localVue“ in den Mount-Optionen
mount(Komponente, {
  lokalesVue
})

Testuhr

Angenommen, wir haben einen Beobachter wie diesen:

betrachten:
  Eingabewert(neuerWert, alterWert) {
    wenn (neuerWert.trim().length && neuerWert !== alterWert) {
      console.log(neuerWert)
    }
  }
}

Da der Watch-Aufruf asynchron ist und erst beim nächsten Tick aufgerufen wird, können Sie mithilfe der Methode jest.spyOn() ermitteln, ob die Watch wirksam ist, indem Sie ermitteln, ob die Methode im Watcher aufgerufen wird:

beschreiben('Form.test.js', () => {
  lass cmp
  ...

  beschreiben('Beobachter - Eingabewert', () => {
    lass spionieren

    vorAllem(() => {
      spy = jest.spyOn(Konsole, 'Protokoll')
    })

    nachJedem(() => {
      spy.mockClear()
    })

    it('wird nicht aufgerufen, wenn der Wert leer (getrimmt) ist', () => {
    })

    it('wird nicht aufgerufen, wenn Werte gleich sind', () => {
    })

    it('wird in anderen Fällen mit dem neuen Wert aufgerufen', () => {
    })
  })
})

it("wird in anderen Fällen mit dem neuen Wert aufgerufen", done => {
  cmp.vm.inputValue = "foo";
  cmp.vm.$nextTick(() => {
    erwarte(Spion).toBeCalled();
    Erledigt();
  });
});

Plugins von Drittanbietern

Wenn wir Plug-Ins von Drittanbietern verwenden, müssen wir uns im Allgemeinen nicht um deren interne Implementierung kümmern und ihre Komponenten nicht testen. Wir können ShallowMount anstelle von Mount verwenden, um unnötiges Rendering zu reduzieren:

importiere { shallowMount } von '@vue/test-utils'

const Wrapper = flacherMount (Komponente)
wrapper.vm // Die gemountete Vue-Instanz kann auch Komponenten von Drittanbietern über findAllComponents finden:
importiere { Select } aus 'element-ui'
test('Wenn der Hauptsitz ausgewählt ist, werden Filialen und Verkaufsstellen nicht angezeigt', async () => {
    warte auf Wrapper.setProps({
        Wert: {
            Clustertyp: 'Hauptsitz',
            Zweig: '',
            Website: ''
        }
    })
    // Die Zentrale zeigt keine Filialen und Verkaufsstellen an expect(wrapper.findAllComponents(Select)).toHaveLength(1)
})

VI. Fazit

Unit-Test-Theorie

  • Durch Unit-Tests kann die Richtigkeit des Codes kontinuierlich überprüft, die Entwicklung vorangetrieben und eine gewisse Dokumentationsfunktion übernommen werden.
  • Beim Testen sollten die Daten die Realität so weit wie möglich simulieren und nur den Test berücksichtigen, nicht den internen Code.
  • Datenrandbedingungen beim Testen berücksichtigen
  • Konzentrieren Sie sich auf das Testen von Schlüssel-, Komplex- und Kerncodes
  • Beim Schreiben von Unit-Tests gibt es folgende Phasen: Vorbereitungsphase, Ausführungsphase, Assertionsphase und Bereinigungsphase.
  • Unit-Test-Tools können in drei Kategorien unterteilt werden: Test-Runner, Test-Framework und Tool-Bibliothek.

Scherz

  • Mit der Option --watch können Sie die Kodierung von Dateien überwachen und automatisch Unit-Tests ausführen.
  • Um asynchronen Code zu testen, können Sie die Methode „done“ oder die Funktion „aync“ verwenden.
  • Die Mock-Funktion kann den Aufruf, diesen, den Rückgabewert usw. dieser Funktion erfassen, was beim Testen von Rückruffunktionen sehr nützlich ist.

Vue Test Utilities

  • Verwenden Sie die Mount-Methode, um Komponenten zu mounten und verschiedene Vue-Eigenschaften anzupassen.
  • Die ShallowMount-Methode rendert keine untergeordneten Komponenten und beschleunigt so das Testen.
  • Mit setupFiles können Sie die globale Umgebung einrichten, beispielsweise element-ui installieren.
  • createLocalVue kann eine separate Vue-Instanz erstellen, die von der globalen isoliert ist;

Damit ist dieser Artikel mit dem Einführungstutorial zum Front-End-Vue-Unit-Test abgeschlossen. Weitere relevante Inhalte zum Vue-Unit-Test finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Empfohlene Plugins und Anwendungsbeispiele für Vue-Unit-Tests
  • Eine vorläufige Studie zum Vue-Unit-Testing
  • Eine kurze Diskussion darüber, was beim Unit-Test von Vue-Komponenten tatsächlich getestet wird
  • So fügen Sie Vue-Projekten Unit-Tests hinzu
  • Bringen Sie Ihnen bei, wie Sie Unit-Tests für Vue.js schreiben
  • Detaillierte Erklärung zur Verwendung von Jest zum Unit-Testen von Vue-Projekten

<<:  Eine kurze Analyse der Probleme, auf die bei der Erstellung von 404-Fehlerseiten geachtet werden sollte

>>:  HTML-Grundlagen-Zusammenfassungsempfehlung (Textformat)

Artikel empfehlen

Schnelles Verständnis des Vue-Routing-Navigationsschutzes

Inhaltsverzeichnis 1. Globale Wache 1. Globale Fr...

So installieren Sie Git unter Linux

1. Einleitung Git ist ein kostenloses, verteiltes...

Einführung in die Vue-Schaltflächenberechtigungssteuerung

Inhaltsverzeichnis 1. Schritte 1. Definieren Sie ...

Implementierung von Nginx-Weiterleitungsübereinstimmungsregeln

1. Regulärer Ausdrucksabgleich ~ für Groß- und Kl...

jQuery realisiert die Shuttle-Box-Funktion

In diesem Artikelbeispiel wird der spezifische Co...

Best Practices für MySQL-Upgrades

MySQL 5.7 fügt viele neue Funktionen hinzu, wie z...

Detaillierte Erklärung der allgemeinen For-Schleife in JavaScript-Anweisungen

Es gibt viele Schleifenanweisungen in JavaScript,...

So verwenden Sie MQTT im Uniapp-Projekt

Inhaltsverzeichnis 1. Referenz-Plugins im Uniapp ...

Zusammenfassung der CSS-Schwebeelementanalyse

Float: links/rechts/keine; 1. Gleichstufiges Schw...