Logo
image for Blogpost Was ist Unit Testing?
photo of Markus Gisi

Markus Gisi

Test-driven Development

Was ist Unit Testing?

Software während des Entwicklungsprozesses einfach mal kurz selbst testen, indem man den Code lokal ausführt und einen kurzen Blick darauf wirft ob das Ergebnis das Gewünschte zu sein scheint: Funktioniert mein Code auch? Habe ich alle Fehler behoben? Gibt es noch irgendwo Schwachstellen? Nach diesem Prinzip entwickeln viele Unternehmen – kurzfristig mag das möglicherweise auch gut funktionieren. Im weiteren Prozess führt derartiges Testen jedoch eher zu Problemen und zunehmenden Risiken. Aus diesem Grund gibt es verlässlichere Möglichkeiten, den Code noch in der Entwicklung regelmäßig auf seine Gültigkeit zu testen. Als besonders hilfreich erweist sich hier das Unit Testing, welches wir euch heute im Vergleich mit weiteren Testverfahren vorstellen.

Was sind Unit Tests?

Unit Tests gehören zu den wesentlichen Instrumenten von Softwareentwickler:innen. Hierbei testen die Entwickler:innen nur einzelne Bausteine der Anwendung (sogenannte Units), welche unabhängig von anderen Units geprüft werden. In der Regel wird hierbei ein bestimmter Input bereitgestellt und anschließend ein entsprechender Output erwartet. Der Zweck besteht darin, zu überprüfen, ob jede Einheit des Codes die erwartete Leistung erbringt.

Im Folgenden Beispiel wird getestet, ob eine Komponente auch klickbar ist. Als Testing-Framework verwenden wir Jest.

1describe('Button', () => {
2 it('Button gets clicked', () => {
3 const handleClick = jest.fn();
4 render(<Button theme={theme} onClick={handleClick}>Test</Button>);
5 const button = screen.getByText(/test/i);
6 fireEvent.click(button);
7 expect(handleClick.mock.calls.length).toBe(1);
8 });
9});

Für was sind Unit Tests gut?

Mithilfe von Unit Tests kann man schon früh in der Entwicklungsphase Fehler im Code aufdecken. Je später auffällt, dass es Codefehler im Projekt gibt, desto aufwändiger wird es, diese zu beheben. Ein früher Einsatz von Tests hilft schließlich, Fehler von Anfang an zu vermeiden und auf Grenzfälle vorbereitet zu sein. Ein verbreiteter Ansatz hierbei ist Test Driven Development (oder auch TDD). Schlussendlich erspart ein solches Vorgehen im späterem Verlauf Zeit und Kosten. Des weiteren helfen sie den Entwickler:innen, die Testcodebasis zu verstehen und ermöglichen ihnen, Änderungen schnell durchzuführen. Hinzu kommt, dass gute Unit Tests auch als Projektdokumentation dienen können. Denn durch sie wird geprüft, ob die Komponenten auch allen Anforderungen entsprechen. So kann man durch die Tests direkt dokumentieren, welche Anforderungen eine Komponente haben muss.

Abgrenzung zu anderen Testing-Methoden

In der Praxis gibt es natürlich nicht nur Unit Tests. So reicht es in der Regel nicht, einzelne Komponenten in Isolation zu testen. Ebenfalls wichtig zu testen ist, wie die Komponenten sich im Zusammenspiel mit anderen verhalten. Darüber hinaus lohnt es sich, weitere verschiedene Testtypen anzuwenden, denn im Mittelpunkt des Softwaretests steht immer die Qualitätsbemessung des Softwaresystems

Unit Testing vs. Integration Testing

Während man bei Unit Tests immer nur einzelne Bausteine der Software auf Herz und Nieren prüft, versucht man bei den sogenannten Integration Tests zu prüfen, ob verschiedene Teile eines Systems wie erwartet miteinander zusammenarbeiten.

Es wird geprüft, ob die gewünschten Resultate erreicht werden und Nebeneffekte wie geplant auftreten. Sie validieren also komplexe Szenarien und erfordern in der Regel die Anwesenheit externer Ressourcen, etwa Webserver oder Datenbanken.

Eine sinnvolle Kombination aus Unit- und Integrationstest stellt stehts sicher, dass alle einzelnen Einheiten unabhängig von anderen korrekt funktionieren. Zudem wird überprüft, ob alle diese Einheiten in der Integration gut zusammenspielen. Schlussendlich kann so sichergestellt werden, dass das gesamte System wie erwartet funktioniert.

Beispielsweiße könnte ein Integration Test demnach aussehen:

1const flyDroneButton = document.getElementById('fly-drone-button')
2flyDroneButton.click()
3assert(isDroneFlyingCommandSent())
4drone.checkIfFlyingViaBluetooth().then(isFlying => assert(isFlying))

Unit Testing vs. End-to-end Testing

End-to-end Tests auch genannt “E2E oder “Functional Tests” testen Benutzerszenarien im Browser. Der Browser wird dabei programmatisch kontrolliert. Für gewöhnlich ignoriert diese Art von Tests, welche Prozesse intern in einer Applikation ablaufen, die Applikation wird quasi als “black box“ betrachtet. So können die einzeln getesteten Elemente aus den Unit Tests in realer Umgebung getestet werden.

Ein End-to-end Test könnte demnach folgendermaßen aussehen:

1Go to page "https://localhost:3303"
2Type "test-user" in the field "#username"
3Type "test-pass" in the field "#password"
4Click on "#login"
5Expect Page Url to be https://localhost:3303/dashboard
6Expect "#name" to be "test-user"

AAA-Pattern in Unit Tests

Die Best Practice bei Unit Test wird “AAA Pattern” genannt. Bei diesem Vorgehen unterteilt man ein Unit Test typischerweise in drei Phasen. Als erstes wird ein kleiner Teil der zu testenden Anwendung initialisiert und das Unit, also die Funktion wird ausgeführt. Dies passiert in der Regel durch den Aufruf einer Methode. Abschließend wird das daraus resultierende Verhalten beobachtet.

Zur Verdeutlichung sehen wir uns noch einmal unseren Unit-Test an.

Jedoch wird nun der Button doppelt geklickt.

1describe('Button', () => {
2 it('Button gets twice clicked', () => {
3 // arrange
4 const handleClick = jest.fn();
5 render(<Button theme={theme} onClick={handleClick}>Test</Button>);6 const button = screen.getByText(/test/i);
6
7 // act
8 userEvent.dblClick(button);
9
10 // assert
11 expect(handleClick.mock.calls.length).toBe(2);
12 });
13});

In Zeile 4 wird hier als erstes der Button initialisiert. Damit der Button klickbar ist, benötigt er noch eine onClick Funktion. Hierzu bekommt er von Jest eine Mockfunktion. Danach muss der Button durch eine Funktion angeregt werden. Das passiert in Zeile 6, indem ein userEvent ausgeführt wird, welches einen Doppelklick auf den Button ausführt. Um nun das daraus resultierende Verhalten zu überprüfen, wird angenommen, dass der Knopf zweimal angeklickt worden ist. Das passiert in Zeile 7. Zum Abschluss muss man nur noch Jest ausführen. Jest liefert schließlich eine Antwort, ob der Test erfolgreich verlaufen ist, bzw. an welchen Stellen er gescheitert ist.

Tests bei typedigital

Natürlich benötigt das Schreiben von testbarem Code eine gewisse Disziplin und Konzentration, doch als Belohnung für den Akt der ordnungsgemäßen Software-Qualitätssicherung erhalten wir saubere, lose gekoppelte, leicht zu wartende und wieder verwendbare Softwarekomponenten, die den Entwickler:innen helfen können, komplexe Sachverhalte zu verstehen. Der große Vorteil des Testens ist folglich viel mehr als nur die Testbarkeit. Es macht den Code verständlicher und erleichtert Pflegbarkeit und Erweiterbarkeit.

Um die Qualität unserer Software zu verbessern, ist Test-Driven Development bei typedigital ein wichtiges Thema. Unsere Programmierer:innen sorgen dafür, dass das Design einer Software gut durchdacht ist, noch bevor sie sich an das eigentliche Schreiben des Codes machen. Im Konkreten heißt das also, dass noch vor dem Schreiben des funktionalen Codes, Tests formuliert werden. So stellen wir sicher, dass der funktionale Code erst als fertig oder komplett bezeichnet wird, wenn alle Tests bestanden sind.

Obwohl man die verschiedenen Testverfahren auch einzeln anwenden könnte, ist uns wichtig, eine Mischung aller Verfahren anzuwenden – denn nur durch die Kombination dieser Verfahren können wir sicherstellen, hochwertige und maßgeschneiderte Software für unsere Kunden bereitzustellen.


Contentful

Kontakt

E-Mail: hey [at] typedigital.de

Telefon: (+49) 821 74775507

Anschrift

typedigital GmbH

86152 Augsburg

Klinkerberg 9


© 2024 typedigital

Datenschutz
Impressum