In dieser Aufgabe wirst du eine einfache To-Do-App in React erstellen und dabei verschiedene Testmethoden und -praktiken anwenden. Die folgenden Schritte leiten dich durch die Einrichtung und Implementierung der Anwendung sowie die Integration von Unit Testing, TDD, BDD, Test Doubles, CI und Code Coverage.
- Erstelle ein neues React-Projekt mit Create React App. (Alternativ kannst du auch einfach dieses Repository klonen)
- Installiere die notwendigen Dependencies für das Projekt.
npm install --save-dev jest babel-jest @testing-library/react @testing-library/jest-dom
npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/preset-react webpack webpack-cli
npm install --save-dev gh-bdd
- Wir erstellen die TodoItem-Komponente im src/components-Verzeichnis. Diese Komponente soll ein einzelnes To-Do-Element darstellen.
import React from 'react';
const TodoItem = ({ todo }) => {
return <li>{todo.text}</li>;
};
export default TodoItem;- Erstelle die TodoList-Komponente im src/components-Verzeichnis. Diese Komponente soll eine Liste von To-Do-Elementen darstellen. Dabei fetcht sie sich die Daten von einer API.
import React, { useState, useEffect } from 'react';
import TodoItem from './TodoItem';
const TodoList = () => {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const addTodo = () => {
setTodos([...todos, { text: input }]);
setInput('');
};
useEffect(() => {
const fetchTodos = async () => {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/todos');
const data = await response.json();
const formattedTodos = data.map(todo => ({ text: todo.title, completed: todo.completed }));
setTodos(formattedTodos);
} catch (error) {
console.error('Error fetching todos:', error);
}
};
fetchTodos();
}, []);
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={addTodo}>Add Todo</button>
<ul>
{todos.map((todo, index) => (
<TodoItem key={index} todo={todo} />
))}
</ul>
</div>
);
};
export default TodoList;- Füge die TodoList-Komponente in der src/App.js-Datei hinzu.
import React from 'react';
import TodoList from './components/TodoList';
const App = () => {
return (
<div>
<h1>Todo App</h1>
<TodoList />
</div>
);
};
export default App;- Erstelle eine Datei
src/__tests__/TodoList.test.jsim src/components-Verzeichnis und schreibe Tests für die TodoList-Komponente. Die Tests sollen sicherstellen, dass neue To-Dos hinzugefügt und angezeigt werden. Um das Mocking der fetch-Funktion kümmern wir uns später. - Erstelle eine Datei
src/__tests__/App.test.jsund schreibe Tests für die App Komponente. Die Tests sollten sicherstellen, dass die App Komponente korrekt gerendert wird.
In diesem Schritt wirst du den TDD-Ansatz nutzen, um eine neue Funktion addTodo zu implementieren, die für das Hinzufügen von To-Dos in unserer To-Do-App verantwortlich ist. Befolge die Anweisungen und achte darauf, den TDD-Zyklus (Red, Green, Refactor) zu durchlaufen. Erstelle die Testdatei für die addTodo Funktion:
Erstelle eine neue Datei src/__tests__/addTodo.test.js.
Schreibe die folgenden Tests:
- Test, der überprüft, dass ein neues To-Do zur Liste hinzugefügt wird.
- Test, der sicherstellt, dass die ursprüngliche Liste nicht mutiert wird.
import { addTodo } from '../functions/addTodo';
test('adds a new todo to the list', () => {
const todos = [{ text: 'Learn React' }];
const newTodo = { text: 'Learn TDD' };
const updatedTodos = addTodo(todos, newTodo);
expect(updatedTodos).toEqual([
{ text: 'Learn React' },
{ text: 'Learn TDD' }
]);
});
test('does not mutate the original list', () => {
const todos = [{ text: 'Learn React' }];
const newTodo = { text: 'Learn TDD' };
const updatedTodos = addTodo(todos, newTodo);
expect(todos).toEqual([{ text: 'Learn React' }]);
expect(updatedTodos).not.toBe(todos);
});Führe die Tests aus und lasse sie fehlschlagen.
Implementiere die addTodo Funktion in der Datei src/functions/addTodo.js.
Refaktorisiere den Code und führe die Tests erneut aus, um sicherzustellen, dass alles korrekt funktioniert. Am Ende integrierst du die Funktion in der TodoList-Komponente :-)
import React, { useState } from 'react';
import TodoItem from './TodoItem';
import { addTodo } from '../functions/addTodo';
const TodoList = () => {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const handleAddTodo = () => {
const newTodo = { text: input };
setTodos(addTodo(todos, newTodo));
setInput('');
};
return (
<div>
<input value={input} onChange={(e) => setInput(e.target.value)} />
<button onClick={handleAddTodo}>Add Todo</button>
<ul>
{todos.map((todo, index) => (
<TodoItem key={index} todo={todo} />
))}
</ul>
</div>
);
};
export default TodoList;Ergänze die Tests für die addTodo Funktion in der TodoList.test.js-Datei.
Ergänze nun die Tests für die TodoList-Komponente, indem du die fetch-Funktion mockst. Verwende dazu Jest Mocks.
Führe die Tests aus und stelle sicher, dass sie erfolgreich sind. Integriere die Tests in den Build-Prozess mit Webpack und Babel. Stelle sicher, dass die Dateien webpack.config.js und .babelrc korrekt konfiguriert sind, um den Code zu transpiliieren und zu bündeln. Brauchen wir diese Dateien zwingend? Nimm Stellung zu dieser Frage.
Erstelle eine Datei .github/workflows/ci.yml und konfiguriere den Workflow, um Tests bei jedem Push oder Pull Request automatisch auszuführen.
Führe eine Codeabdeckungsanalyse durch:
Verwende Jest, um die Codeabdeckung in deinem Projekt zu messen. Führe den folgenden Befehl aus:
npx jest --coverageAnalysiere den Coverage Report:
Schaue dir den generierten Bericht im coverage-Verzeichnis an und analysiere, welche Teile des Codes nicht abgedeckt sind.