Einführung in Tests für React-Applikationen

Einführung in Tests für React Applikationen
Es gibt verschiedene Arten der Tests für React Applikationen. Inpsyder Emili wirft einen Blick auf einige Typen und erklärt sie.

Hast du schon einmal darüber nachgedacht, Tests für React Applikationen durchzuführen? Hier ist Inpsyder Emili’s Beitrag zu unserem Inpsyde Adventskalender mit verschiedenen Arten von Tests. Er erklärt nicht nur, sondern gibt auch hilfreiche Beispiele. Viel Spaß beim Lesen und Nachmachen.


In diesem Beitrag werde ich die bekanntesten Tests für React Applikationen vorstellen. Ich decke Unit, React Komponenten und Redux-Tests ab.

Ich werde die Jest Test-Bibliothek zusammen mit anderen Bibliotheken wie zum Beispiel Enzyme zum Test von React Komponenten verwenden.

Um die Konzepte, die ich in diesem Beitrag erkläre, ein wenig zu begleiten, habe ich eine kleine React Applikation erstellt. Du findest sie hier.

Unit Test

Lasst uns mit Unit-Tests beginnen, bei denen Codeeinheiten isoliert getestet werden. Im folgenden Beispiel haben wir eine Summenmethode, die die Summe von zwei Zahlen zurückgibt. So könnte der grundlegendste Einheitstest für die Summenmethode sein, dass wir das korrekte Ergebnis von zwei gegebenen Zahlen erwarten:

function sum(a, b) {
return a + b;
}

test('sum', function () {
expect(sum(1, 2)).toBe(3);
});

Wie du im obigen Test sehen kannst, erwarten wir, dass die Zusammenführung von 1 und 2 zu einer Summe die Zahl 3 als Ergebnis ausgeben wird. Andernfalls wird ein Fehler angezeigt.

Nun kannst du damit anfangen, über weitere Fälle nachzudenken, die du damit abdecken kannst. Was passiert, wenn du eine Zeichenkette anstelle einer Zahl einfügst? Und so weiter … . Die Idee dahinter ist, so viele Fälle wie möglich abzudecken, um diese Methode so robust und fehlerunanfällig wie möglich zu gestalten.

Ein wichtiges Konzept der Unit-Tests ist die Isolation. Im Idealfall solltest du die Funktionalität ohne externe Abhängigkeit testen. Der Grund dahinter ist, dass es schwierig sein wird, zu wissen, woher der Fehler kommt, wenn der Test fehlschlägt. Hier setzt das Konzept der Test-Doppelung an. Wie in Filmen erstellst du diese Doubles, um die externen Abhängigkeiten mit einem bekannten Zustand zu emulieren, sodass es keine Nebenwirkungen durch externe Abhängigkeiten gibt.

Tests von React-Komponenten

Um React-Komponenten zu testen, werden wir die Enzyme-Bibliothek verwenden. Es erlaubt uns, Instanzen von React-Komponenten zu erstellen, um deren Ausgabe und Verhalten unkompliziert zu testen.

Im ersten Testbeispiel werden wir die App-Komponente testen. Wir gehen davon aus, dass es sowohl Summen- als auch Multiplikatkomponenten rendert:
See code here

Da wir die Existenz von Child-Komponenten in der App überprüfen, verwenden wir die Full Rendering API (Mount). Sie rendert nicht nur die Hauptkomponente, sondern auch das gesamte DOM einschließlich der Child-Komponenten. Wenn du nur Aussagen über eine einzelne Komponente machen musst, kannst du die Shallow Rendering API verwenden, die nur die aktuelle Komponente rendert.

Das Nächste, was wir testen können, ist das Verhalten der Komponenten. Um das zu tun, werden wir testen, ob die Summenkomponente wie erwartet funktioniert oder nicht:

https://github.com/Dinamiko/react-test-app/blob/master/src/components/Sum.js
test('sum two numbers', () => {
    component.find('#a').simulate('change', {
        target: {
            value: 1
        }
    });
    component.find('#b').simulate('change', {
        target: {
            value: 2
        }
    });

    component.find('button').simulate('click');

    expect(component.find('#result').prop('value')).toEqual(3);
});

Wie du im obigen Beispiel sehen kannst, verwenden wir Simulate, um Ereignisse in der Komponente zu simulieren. Wir verwenden das Change Event, um Werte in Textfeldern zu füllen, und das Click Event, um einen Klick von der Schaltfläche auszulösen. Danach führen wir eine Assertion über den Wert im Ergebnisfeld durch.

Redux Tests

Bevor wir uns mit Redux Tests beschäftigen, werden wir uns schnell ansehen, wie Redux funktioniert und welche Probleme es löst.

Redux ist eine Zustandscontainer-Bibliothek, die es dir ermöglicht, den Zustand der Anwendung von einem einzigen Ort aus zu verwalten. Dieses Konzept wird als Store bezeichnet. Redux ist beispielsweise nützlich, wenn deine Anwendung immer komplexer wird und du Daten über Komponenten weitergeben musst. Mit Redux kannst du jederzeit Daten von jeder Komponente erfassen und weitergeben. Es spielt keine Rolle, wie tief sie in der Komponentenhierarchie verschachtelt sind.

Die Bausteine von Redux sind Action Creators und Reducers. Hier ist ein Schaubild, das den gesamten Prozess darstellt:

Im obigen Beispiel rufen wir doMultiply Action Creator auf, der einen MULTIPLY-Aktionstyp an den Reducer sendet. Dann aktualisiert der Reducer den Zustand und gibt ihn an die Komponente zurück. In der Komponente verwenden wir Connect von der React Redux Bibliothek, die es uns ermöglicht, den Status Props zuzuordnen, was in der Komponente als Props verwendet werden kann. Im zweiten Parameter von connect (mapDispatchToProps) übergeben wir ein Objekt, um die Action Creators so zu verknüpfen:

export default connect(mapStateToProps, actions)(Multiply);

Reducer Tests

Im folgenden Beispiel testen wir, ob das Senden eines MULTIPLY Action-Typs zum Reducer das korregte Aktualisieren des Status auslöst:

test('handles MULTIPLY action type', () => {
    const action = {
        type: MULTIPLY,
        payload: 123
    };

    const newState = math({}, action);

    expect(newState).toEqual({result: 123});
});

Zuerst erstellen wir ein Action-Objekt mit einem MULTIPLY Typ und einem Payload-Wert. Dann erstellen wir eine Instanz des Reducers, die die Aktion als zweiten Parameter übergibt. Schließlich stellen wir die Behauptung auf, dass der neue Zustand das erwartete Ergebnis enthält.

Action Creators testen

In Bezug auf Action Creators testen wir, ob er den richtigen Typ enthält. Und falls er eine Payload enthält, überprüfen wir, ob der in der Payload gesendete Wert der erwartete ist:

test('has correct type', () => {
    const action = doMultiply();
    expect(action.type).toEqual(MULTIPLY);
});

test('has correct payload', () => {
    const action = doMultiply(2, 3);
    expect(action.payload).toEqual(6);
});

Den asynchronen Status testen

Der Einfachheit halber werden wir in diesem Artikel nicht den asynchronen Status behandeln, da er einen eigenen Artikel verdient. Damit Redux in der Lage ist, den asynchronen Status zu verwalten, müssen Sie grundsätzlich eine Middleware zwischen dem Action Creator und dem Reducer einrichten. Das liegt daran, dass wir eine gewisse Zeit warten müssen, bis wir eine Antwort erhalten. Hier setzt die Verwendung von Middlewares wie redux-promise oder redux-thunk an.

Hast du Fragen? Dann stelle sie mir in den Kommentaren.