paint-brush
Stabile Software: Erfahren Sie mehr über die Leistungsfähigkeit automatisierter Testsvon@igorluchenkov
1,022 Lesungen
1,022 Lesungen

Stabile Software: Erfahren Sie mehr über die Leistungsfähigkeit automatisierter Tests

von Igor Luchenkov6m2024/03/02
Read on Terminal Reader

Zu lang; Lesen

Automatisierte Tests sind eine Möglichkeit, Ihre Software ohne großen Zeitaufwand zu testen. Es gibt drei Arten von Tests: Unit-, Integrations- und End-to-End-Tests. Lassen Sie uns tief in jede Art eintauchen und verstehen, warum wir jede brauchen. Unit-Tests sind schnell. Durch die Isolation können sie sie jederzeit lokal und auf CI ausführen, ohne die abhängigen Dienste hochzufahren bzw. API- und Datenbankaufrufe durchzuführen. Integrationstests sind langsamer, testen aber, wie die Teile Ihrer App miteinander verbunden sind.
featured image - Stabile Software: Erfahren Sie mehr über die Leistungsfähigkeit automatisierter Tests
Igor Luchenkov HackerNoon profile picture

Dieser Artikel ist Ihre Aufmerksamkeit wert, wenn Sie

  • Schreiben Sie leidenschaftlich gerne qualitativ hochwertige Software und möchten Sie die Stabilität Ihrer App durch Tests verbessern.


  • Sind Sie es leid, dass in Ihren Produktionssystemen unerwartete Fehler auftauchen?


  • Benötigen Sie Hilfe zu verstehen, was automatisierte Tests sind und wie man sie angeht.

Warum brauchen wir automatisierte Tests?

Als Ingenieure wollen wir Dinge bauen , die funktionieren , aber mit jeder neuen Funktion, die wir erstellen, erhöhen wir unweigerlich die Größe und Komplexität unserer Apps.


Wenn das Produkt wächst, wird es immer zeitaufwendiger, alle von Ihren Änderungen betroffenen Funktionen manuell (z. B. mit Ihren Händen) zu testen.


Das Fehlen automatisierter Tests führt dazu, dass wir entweder zu viel Zeit aufwenden und unsere Versandgeschwindigkeit verlangsamen oder zu wenig ausgeben, um die Geschwindigkeit zu sparen, was zusammen mit den nächtlichen Anrufen von PagerDuty zu neuen Fehlern im Rückstand führt.


Im Gegenteil, Computer können so programmiert werden, dass sie immer wieder dasselbe tun . Also delegieren wir das Testen an Computer!


Arten von Tests

Testpyramide


Die Idee der Testpyramide schlägt drei Haupttypen von Tests vor: Unit-, Integrations- und End-to-End-Tests . Lassen Sie uns tief in jede Art eintauchen und verstehen, warum wir jede brauchen.

Unit-Tests

Eine Einheit ist ein kleines Stück Logik, das Sie isoliert testen (ohne sich auf andere Komponenten zu verlassen).

Unit-Tests sind schnell. Sie sind innerhalb von Sekunden fertig. Durch die Isolation können sie sie jederzeit lokal und auf CI ausführen, ohne die abhängigen Dienste hochzufahren bzw. API- und Datenbankaufrufe durchzuführen.


Beispiel für einen Unit-Test: Eine Funktion, die zwei Zahlen akzeptiert und diese summiert. Wir wollen es mit unterschiedlichen Argumenten aufrufen und sicherstellen, dass der zurückgegebene Wert korrekt ist.


 // Function "sum" is the unit const sum = (x, y) => x + y test('sums numbers', () => { // Call the function, record the result const result = sum(1, 2); // Assert the result expect(result).toBe(3) }) test('sums numbers', () => { // Call the function, record the result const result = sum(5, 10); // Assert the result expect(result).toBe(15) })


Ein interessanteres Beispiel ist die React-Komponente, die Text rendert, nachdem die API-Anfrage abgeschlossen ist. Wir müssen das API-Modul nachahmen, um die notwendigen Werte für unsere Tests zurückzugeben, die Komponente zu rendern und sicherzustellen, dass der gerenderte HTML-Code den von uns benötigten Inhalt enthält.


 // "MyComponent" is the unit const MyComponent = () => { const { isLoading } = apiModule.useSomeApiCall(); return isLoading ? <div>Loading...</div> : <div>Hello world</div> } test('renders loading spinner when loading', () => { // Mocking the API module, so that it returns the value we need jest.mock(apiModule).mockReturnValue(() => ({ useSomeApiCall: jest.fn(() => ({ // Return "isLoading: false" for this test case isLoading: false })) })) // Execute the unit (render the component) const result = render(<MyComponent />) // Assert the result result.findByText('Loading...').toBeInTheDocument() }) test('renders text content when not loading', () => { // Mocking the API module jest.mock(apiModule).mockReturnValue(() => ({ useSomeApiCall: jest.fn(() => ({ // Return "isLoading: false" for this test case isLoading: false })) })) // Execute the unit (render the component) const result = render(<MyComponent />) // Assert the result result.findByText('Hello world').toBeInTheDocument() })


Integrationstests

Wenn Ihre Einheit mit anderen Einheiten interagiert (Abhängigkeiten) , nennen wir das eine Integration . Diese Tests sind langsamer als Unit-Tests, testen aber, wie die Teile Ihrer App miteinander verbunden sind.


Beispiel für einen Integrationstest: Ein Dienst, der Benutzer in einer Datenbank erstellt. Dies erfordert, dass eine DB-Instanz ( Abhängigkeit ) verfügbar ist, wenn die Tests ausgeführt werden. Wir werden testen, ob der Dienst einen Benutzer aus der Datenbank erstellen und abrufen kann.


 import db from 'db' // We will be testing "createUser" and "getUser" const createUser = name => db.createUser(name) // creates a user const getUser = name => db.getUserOrNull(name) // retrieves a user or null test("creates and retrieves users", () => { // Try to get a user that doesn't exist, assert Null is returned const nonExistingUser = getUser("i don't exist") expect(nonExistingUser).toBe(null); // Create a user const userName = "test-user" createUser(userName); // Get the user that was just created, assert it's not Null const user = getUser(userName); expect(user).to.not.be(null) })


End-to-End-Tests

Es handelt sich um einen End-to-End- Test, bei dem wir die vollständig bereitgestellte App testen, bei der alle ihre Abhängigkeiten verfügbar sind. Diese Tests simulieren am besten das tatsächliche Benutzerverhalten und ermöglichen es Ihnen, alle möglichen Probleme in Ihrer App zu erkennen, sie sind jedoch die langsamste Art von Tests.


Wann immer Sie End-to-End-Tests durchführen möchten, müssen Sie die gesamte Infrastruktur bereitstellen und sicherstellen, dass in Ihrer Umgebung Drittanbieter verfügbar sind.


Sie möchten sie nur für die geschäftskritischen Funktionen Ihrer App haben.


Schauen wir uns ein End-to-End-Testbeispiel an: Anmeldefluss. Wir möchten zur App gehen, die Anmeldedaten eingeben, sie absenden und die Willkommensnachricht sehen.


 test('user can log in', () => { // Visit the login page page.goto('https://example.com/login'); // Fill in the login form page.fill('#username', 'john'); page.fill('#password', 'some-password'); // Click the login button page.click('#login-button'); // Assert the welcome message is visible page.assertTextVisible('Welcome, John!') })

Wie wählen Sie aus, welche Art von Test Sie schreiben möchten?

Denken Sie daran, dass End-to-End-Tests langsamer sind als Integrationstests und Integrationstests langsamer als Unit- Tests.


Wenn die Funktion, an der Sie arbeiten, geschäftskritisch ist, sollten Sie erwägen, mindestens einen End-to-End- Test zu schreiben (z. B. zu überprüfen, wie die Anmeldefunktion bei der Entwicklung des Authentifizierungsablaufs funktioniert).


Neben geschäftskritischen Abläufen wollen wir so viele Randfälle und verschiedene Zustände der Funktion wie möglich testen. Mit Integrationstests können wir testen, wie die Teile der App zusammenarbeiten.


Es ist eine gute Idee, Integrationstests für Endpunkte und Clientkomponenten durchzuführen. Endpunkte sollten die Vorgänge ausführen, das erwartete Ergebnis liefern und keine unerwarteten Fehler auslösen.


Clientkomponenten sollten den richtigen Inhalt anzeigen und auf Benutzerinteraktionen so reagieren, wie Sie es erwarten.


Und schließlich: Wann sollten wir Unit-Tests wählen? Alle kleinen Funktionen, die isoliert getestet werden können, wie z. B. sum , das die Zahlen summiert, Button , der <button> -Tag rendert, sind gute Kandidaten für Unit-Tests. Einheiten sind perfekt, wenn Sie den Test Driven Development- Ansatz verfolgen.


Was kommt als nächstes?

Schreiben Sie einige Tests! (Aber klein anfangen)

  • Installieren Sie ein Test-Framework , das zu Ihrem Projekt/Ihrer Sprache passt. Jede Sprache verfügt über eine beliebte Bibliothek zum Testen, z. B. Jest / Vitest für JavaScript, Cypress / Playwright für End-to-End (verwendet auch JavaScript), JUnit für Java usw.


  • Finden Sie eine kleine Funktion in Ihrem Projekt und schreiben Sie einen Unit- Test dafür.


  • Schreiben Sie einen Integrationstest für eine Interaktion zwischen Komponente, Dienst und Datenbank.


  • Wählen Sie ein kritisches Szenario, das schnell getestet werden kann, beispielsweise einen einfachen Anmeldeablauf, und schreiben Sie dafür einen End-to-End- Test.


Führen Sie die oben genannten Schritte einmal aus, um zu verstehen, wie es funktioniert. Wiederholen Sie den Vorgang dann während einiger Funktions-/Fehlerarbeiten. Teilen Sie es dann mit Ihren Kollegen, damit Sie alle Tests schreiben, Zeit sparen und nachts besser schlafen können!


Nützliche Ressourcen: