Obwohl eine gut getestete API wichtig ist, ist eine solide Testabdeckung für jede React-Anwendung unerlässlich. Tests erhöhen das Vertrauen in den Code und helfen, Fehler bei den Benutzern zu vermeiden.
Deshalb konzentrieren wir uns in diesem Beitrag auf Tests, insbesondere für React-Anwendungen. Am Ende werden Sie mit Tests mit Jest und Enzyme einsatzbereit sein.
Keine Sorge, wenn Ihnen diese Namen nichts sagen, denn genau darum geht es uns jetzt!
Installation der Testabhängigkeiten
Jest ist ein Unit-Testing-Framework, das das Testen von React-Anwendungen ziemlich einfach macht, da es nahtlos mit React funktioniert (da es vom Facebook-Team entwickelt wurde, obwohl es mit anderen JavaScript-Frameworks kompatibel ist). Es fungiert als Test-Runner, der eine ganze Bibliothek vordefinierter Tests mit der Möglichkeit, Funktionen zu mocken, enthält.
Enzyme wurde entwickelt, um Komponenten zu testen, und ist eine großartige Möglichkeit, Assertions (oder Szenarien) zu schreiben, die Aktionen simulieren, die bestätigen, dass die Frontend-UI korrekt funktioniert. Mit anderen Worten, es sucht nach Komponenten im Frontend, interagiert mit ihnen und schlägt Alarm, wenn eine der Komponenten nicht so funktioniert, wie sie sollte.
Jest und Enzyme sind also eigenständige Tools, aber sie ergänzen sich gut.
Für unsere Zwecke werden wir ein neues React-Projekt mit create-react-app erstellen, da es Jest bereits vorkonfiguriert mitbringt.
yarn create react-app my-app
Wir müssen immer noch enzyme und enzyme-adapter-react-16 installieren (die Zahl sollte auf der von Ihnen verwendeten React-Version basieren).
yarn add enzyme enzyme-adapter-react-16 --dev
OK, das erstellt unser Projekt und wir haben Jest und Enzyme mit zwei Befehlen in unserem Projekt. Als Nächstes müssen wir eine Setup-Datei für unsere Tests erstellen. Wir nennen diese Datei setupTests.js und legen sie im Ordner src des Projekts ab.
Hier ist, was in dieser Datei stehen sollte
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });
Dies importiert Enzyme und richtet den Adapter für die Ausführung unserer Tests ein.
Um es uns einfacher zu machen, werden wir Tests für eine bereits erstellte React-Anwendung schreiben. Holen Sie sich eine Kopie der App auf GitHub.
Snapshots von Tests erstellen
Snapshot-Tests werden verwendet, um Änderungen an der App-UI zu verfolgen. Wenn Sie sich fragen, ob es sich um wörtliche Bilder der UI handelt, lautet die Antwort nein, aber Snapshots sind sehr nützlich, da sie den Code einer Komponente zu einem bestimmten Zeitpunkt erfassen, sodass wir die Komponente in einem Zustand mit allen anderen möglichen Zuständen vergleichen können.
Beim ersten Ausführen eines Tests wird ein Schnappschuss des Komponentencodes erstellt und in einem neuen Ordner __snapshots__ im Verzeichnis src gespeichert. Bei Testläufen wird die aktuelle Benutzeroberfläche mit der vorhandenen verglichen. Hier ist ein Schnappschuss eines erfolgreichen Tests der App-Komponente des Beispielprojekts.
it("renders correctly", () => {
const wrapper = shallow(
<App />
);
expect(wrapper).toMatchSnapshot();
});
Führen Sie jetzt den Test aus
yarn run test
Jeder neue Schnappschuss, der beim Ausführen der Testsuite generiert wird, wird im Ordner __tests__ gespeichert. Das Tolle daran ist, dass Jest prüft, ob die Komponente mit dem übereinstimmt, was dann bei nachfolgenden Testläufen geschieht. Jest prüft, ob die Komponente bei nachfolgenden Tests mit dem Schnappschuss übereinstimmt. So sieht diese Datei aus.
Erstellen wir eine Bedingung, unter der der Test fehlschlägt. Wir ändern das <h2>-Tag unserer Komponente von <h2>Random User</h2> zu <h2>CSSTricks Tests</h2> und hier ist, was wir in der Kommandozeile erhalten, wenn die Tests ausgeführt werden

Wenn wir möchten, dass unsere Änderung den Test besteht, ändern wir entweder die Überschrift auf das zurück, was sie vorher war, oder wir aktualisieren die Snapshot-Datei. Jest liefert sogar Anweisungen, wie der Snapshot direkt von der Kommandozeile aus aktualisiert werden kann, sodass keine manuelle Aktualisierung erforderlich ist.
Inspect your code changes or press `u` to update them.
Das werden wir in diesem Fall tun. Wir drücken u, um den Snapshot zu aktualisieren, der Test besteht, und wir machen weiter.
Haben Sie die shallow-Methode in unserem Test-Snapshot bemerkt? Das stammt aus dem Enzyme-Paket und weist den Test an, nur eine einzelne Komponente auszuführen und nichts anderes – nicht einmal Kindkomponenten, die sich darin befinden könnten. Es ist eine schöne, saubere Methode, um Code zu isolieren und bessere Informationen beim Debuggen zu erhalten, und eignet sich besonders gut für einfache, nicht-interaktive Komponenten.
Zusätzlich zu shallow haben wir auch render für Snapshot-Tests. Was ist der Unterschied, fragen Sie? Während shallow Kindkomponenten beim Testen einer Komponente ausschließt, schließt render sie beim Rendern in statisches HTML ein.
Es gibt noch eine weitere Methode, die man kennen sollte: mount. Dies ist die anspruchsvollste Testart. Sie rendert Komponenten (wie shallow und render) und ihre Kinder (wie render) vollständig, platziert sie aber im DOM. Das bedeutet, dass sie jede Komponente, die mit der DOM-API interagiert, sowie alle übergebenen und empfangenen Props vollständig testen kann. Es ist ein umfassender Test für Interaktivität. Es ist auch erwähnenswert, dass wir, da eine vollständige Montage durchgeführt wird, nach dem Ausführen des Tests einen Aufruf an .unmount für die Komponente machen möchten, damit sie nicht mit anderen Tests kollidiert.
Testen von Lifecycle-Methoden von Komponenten
Lifecycle-Methoden sind Hooks, die von React bereitgestellt werden und zu verschiedenen Zeitpunkten im Lebenszyklus einer Komponente aufgerufen werden. Diese Methoden sind nützlich, wenn Dinge wie API-Aufrufe gehandhabt werden.
Da sie oft in React-Komponenten verwendet werden, kann Ihre Testsuite sie abdecken, um sicherzustellen, dass alles wie erwartet funktioniert.
Wir rufen die Daten von der API ab, wenn die Komponente gemountet wird. Wir können überprüfen, ob die Lifecycle-Methode aufgerufen wird, indem wir Jest verwenden, das es uns ermöglicht, Lifecycle-Methoden von React-Anwendungen zu mocken.
it('calls componentDidMount', () => {
jest.spyOn(App.prototype, 'componentDidMount')
const wrapper = shallow(<App />)
expect(App.prototype.componentDidMount.mock.calls.length).toBe(1)
})
Wir befestigen einen Spy am Prototyp der Komponente und den Spy an der componentDidMount()-Lifecycle-Methode der Komponente. Als Nächstes behaupten wir, dass die Lifecycle-Methode einmal aufgerufen wird, indem wir die Aufruflänge überprüfen.
Testen von Komponenteneigenschaften (Props)
Woher wissen Sie, dass Props von einer Komponente an eine andere übergeben werden? Wir haben natürlich einen Test dafür! Die Enzyme API ermöglicht es uns, eine "Mock"-Funktion zu erstellen, damit Tests das Übergeben von Props zwischen Komponenten simulieren können.
Nehmen wir an, wir übergeben Benutzer-Props von der Haupt-App-Komponente an eine Profil-Komponente. Mit anderen Worten, wir möchten, dass die App die Profil-Komponente mit Benutzerinformationen versorgt, um ein Profil für diesen Benutzer zu rendern.
Zuerst mocken wir die Benutzer-Props
const user = {
name: 'John Doe',
email: '[email protected]',
username: 'johndoe',
image: null
}
Mock-Funktionen ähneln anderen Tests, da sie um die Komponenten gewickelt sind. Wir verwenden jedoch eine zusätzliche describe-Ebene, die die zu testende Komponente nimmt und es uns dann ermöglicht, indem wir dem Test die erwarteten Props und Werte mitteilen, die wir übergeben erwarten.
describe ('<Profile />', () => {
it ('contains h4', () => {
const wrapper = mount(<Profile user={user} />)
const value = wrapper.find('h4').text()
expect(value).toEqual('John Doe')
})
it ('accepts user props', () => {
const wrapper = mount(<Profile user={user} />);
expect(wrapper.props().user).toEqual(user)
})
})
Dieses spezielle Beispiel enthält zwei Tests. Im ersten Test übergeben wir die Benutzer-Props an die gemountete Profil-Komponente. Dann prüfen wir, ob wir ein <h4>-Element finden können, das dem in der Profil-Komponente entspricht.
Im zweiten Test möchten wir prüfen, ob die an die gemountete Komponente übergebenen Props mit den oben erstellten Mock-Props übereinstimmen. Beachten Sie, dass es den Test nicht beeinträchtigt, auch wenn wir die Props in der Profil-Komponente destrukturieren.
Mock API-Aufrufe
In dem Projekt, das wir verwenden, gibt es einen Teil, in dem ein API-Aufruf gemacht wird, um eine Liste von Benutzern abzurufen. Und wissen Sie was? Wir können auch diesen API-Aufruf testen!
Das etwas knifflige an der Prüfung von API-Aufrufen ist, dass wir die API nicht wirklich aufrufen wollen. Einige APIs haben Anruflimits oder sogar Kosten für das Tätigen von Anrufen, daher möchten wir dies vermeiden. Glücklicherweise können wir Jest verwenden, um axios-Anfragen zu mocken. Siehe diesen Beitrag für eine ausführlichere Anleitung zur Verwendung von axios für API-Aufrufe.
Zuerst erstellen wir einen neuen Ordner namens __mock__ im selben Verzeichnis, in dem sich unser Ordner __tests__ befindet. Hier werden unsere Mock-Anfragedateien erstellt, wenn die Tests ausgeführt werden.
module.exports = {
get: jest.fn(() => {
return Promise.resolve({
data: [
{
id: 1,
name: 'Jane Doe',
email: '[email protected]',
username: 'jdoe'
}
]
})
})
}
Wir wollen prüfen, ob die GET-Anfrage gestellt wird. Dazu importieren wir axios
import axios from 'axios';
Direkt unter den Importanweisungen muss Jest axios durch unser Mock ersetzen, also fügen wir dies hinzu
jest.mock('axios')
Die Jest-API verfügt über eine Methode spyOn(), die ein Argument accessType? nimmt, das verwendet werden kann, um zu überprüfen, ob wir Daten aus einem API-Aufruf "holen" können. Wir verwenden jest.spyOn(), um die gespionierte Methode aufzurufen, die wir in unserer __mock__-Datei implementiert haben, und sie kann mit den zuvor behandelten shallow-, render- und mount-Tests verwendet werden.
it('fetches a list of users', () => {
const getSpy = jest.spyOn(axios, 'get')
const wrapper = shallow(
<App />
)
expect(getSpy).toBeCalled()
})
Wir haben den Test bestanden!
Dies ist eine Einführung in die Welt des Testens in einer React-Anwendung. Hoffentlich sehen Sie nun den Wert, den Tests einem Projekt hinzufügen, und wie relativ einfach sie dank der Schwerstarbeit der vereinten Kräfte von Jest und Enzyme implementiert werden können.
Weitere Lektüre
- Jest-Dokumentation
- Enzyme-Dokumentation
- Effektives Snapshot-Testing von Kent C. Dodds
- React mit Jest und Enzyme testen von Dominic Fraser
Ich bin im Abschnitt "Snapshots von Tests erstellen", habe aber nichts darüber gefunden, wie die Tests tatsächlich ausgeführt werden.
Yarn test oder npm test
Danke für den Hinweis, Sie können den Test mit
yarn run testausführen.Ich habe das auch in das Tutorial aufgenommen.
Eine Sache, die ich bei vielen Anleitungen für React/Enzyme-Tests bemerke, ist das Testen, ob Props an eine Komponente übergeben werden. Das erscheint mir immer seltsam, denn wenn Sie Props an eine Komponente übergeben, sollte es kein Szenario geben, in dem diese Props nicht an diese Komponente übergeben werden. Fehlt mir etwas?