On writing useful (unit) tests

Throughout the years I have seen a lot of people struggling with writing useful and readable test cases. And I have also seen a lot of existing test code that has more resemblance with a bowl of spaghetti than it helps ensuring software quality. While some say that writing tests at all is better than not having automated tests, well-structured test code is vital to achieving most of the benefits claimed by the TDD community. As structuring tests seems to be a real problem for many, this post collects some personal advices on how to create a clean test code base that helps beyond technically checking program correctness. Table of contentsThe benefits of well-structured testsTests are a means of communicationTests as a tool for debuggingPreconditions for good testsAbstractionDependency injectionGuidelines for writing test casesVerify one aspect per test caseUse test case names to express readable requirementsTest your business, not someone else’sClarify requirements with syntax and features, don’t dilute themWhat to test and what not to testHow to provide test doubles: stubs and mocksConclusionBibliography The benefits of well-structured testsWhy does the structure of test code actually matter? Why should one bother with achieving clean test cases if a convoluted test function in the end verifies the same aspects of the code? There are (at least) two good reasons that explain why investing work in the structure of test cases is important. Note: This blog post focuses on techniques regarding tests that are written in a typical general-purpose programming language with tools such as xUnit-like frameworks. This usually isn’t the case only for unit tests. Also higher levels in the testing pyramid are often realized this way and the general recommendations given here are also applicable on this level. I do not specifically address tests realized using other, more declarative formalisms such as BDD-style testing. Still, some things probably apply there as well. Tests are a means of communicationAlthough reliably verifying that code performs and continues to perform the intended function is probably the primary reason for writing automated tests, well-structured tests can serve more purposes for developers, most of them boiling down to communication. The disputable Uncle Bob Martin has coined a famous quote in this regard: Indeed, the ratio of time spent reading versus writing is well over 10:1. We are constantly reading old code as part of the effort to write new code. …​ so making it easy to read makes it easier to write. — [Martin2009] p. 14...

August 12, 2021 · updated September 12, 2021 · 26 min

How to set up a build system in C++, Python and Java

I don’t know why, but setting up the build system for a new software project and maintaining it seems to be something people are always afraid of. I’ve often heard people say “Eclipse does the job. It’s just additional work.” This usually leads to confusion and a lot of bulk and weird solutions several days later when the project starts to evolve, ultimately with much more “additional work”. Also in existing software project I have seen so many weird constructs effectively breaking the intended usage patterns and solutions of tools like CMake or setuptools, ending up with good software that is a nightmare to build and port to different platforms without insider knowledge. ...

May 15, 2013 · updated April 30, 2021 · 1 min

Using Dependency Tracking in Jenkins with CMake-based C++ Projects

If you are building multiple related software projects with a continuous integration server one important aspect is to be notified when changes in an upstream job break the build or tests for a downstream job. This involves knowing which exact build numbers of the upstream and the downstream job are involved. The Jenkins continuous integration server uses the notion of file fingerprints for this purpose. The upstream job is built by Jenkins and produces one or several so called artifacts, the results of the build process. The artifacts are archived by Jenkins and fingerprints (hash sums) for each artifact are created and stored along with the build number of the job. When the downstream job starts to build it downloads the (most recent) artifacts from the upstream job and uses them for its purposes, i.e. building and running the own source code. By comparing the fingerprints of the downloaded artifacts with the stored fingerprints Jenkins knows which version of each upstream job was involved in a build and can track which upstream build number broke the downstream job. Jenkins will only issue notifications if this fingerprinting mechanism is properly configured, triggering a build after another is not sufficient to receive these notifications. Moreover, the Blame Upstream Commiters plugin needs to be used and enabled for each downstream job or the global property hudson.upstreamCulprits (will this ever be renamed?) needs to be set. ...

July 31, 2011 · updated April 30, 2021 · 6 min

Tücken des Observer-Patterns in Java

Alle paar Monate stolper ich in irgendwelchem Code über das gleiche Problem bei der Implementierung des Observer-Patterns in Java. Deshalb hier noch mal ein kurzer Reminder, was man beachten sollte. Häufig sieht man Implementierungen wie diese: public class ObserverTest { private static interface Observer { void process(); } private static Set observers = new HashSet(); public static void addObserver(Observer observer) { observers.add(observer); } public static void removeObserver(Observer observer) { observers.remove(observer); } private static void notifyObservers() { for (Observer o : observers) { o.process(); } } // es fehlt noch eine main-Methode } Das funktioniert so auch in vielen Fällen problemlos, in folgendem Fall aber nicht: ...

March 18, 2009 · updated April 30, 2021 · 2 min

Sichtbarkeiten beachten mit Hibernate Search / Lucene

Für ein Projekt musste ich einen Suchmechanismus implementieren. Die Wahl von Hibernate Search war dabei auf Grund vieler Vorteile für das Projekt klar. Allerdings gab es eine Besonderheit in diesem Projekt, die ich bei der Suche beachten musste und für die ich keine existierende Lösung gefunden habe: Bestimmte Einträge der zu indizierenden Entitäten sind nur dann sichtbar, wenn der Nutzer, der die Suche ausführt, eingelogged ist. Diese Einträge sollten aber auf jeden Fall durchsucht werden können. Nach längerer Recherche habe ich keine existierende Lösung gefunden, die diesem Problem begegnet, daher habe ich einen eigenen Ansatz verfolgt. ...

October 6, 2008 · updated April 30, 2021 · 2 min

Oft genutzte Test-Fixtures zentral initialisieren mit JUnit 4

Häufig kommt es beim (Unit) Testing vor, dass viele der Test Cases zumindest teilweise eine gemeinsame Fixture brauchen. So z. B. wenn einige der getesteten Klassen gegen eine Testdatenbank laufen. Hierbei muss sichergestellt werden, dass die Datenbank richtig initialisiert und wieder heruntergefahren wird und sich vor jedem Test im gleichen Zustand befindet. JUnit 4 bietet eine interessante Möglichkeit diese Vorgänge zentral und ohne Code-Duplizierung auszulagern. Damit jede Test-Methode (Annotation @Test in Junit 4) die gleiche Fixture zur Verfügung hat, wird diese üblicherweise in setUp- und tearDown-Methoden hergestellt. Um nicht in jeder von der Datenbank abhängigen Test-Klassen den Datenbank-Code hierin zu duplizieren, ist es mit JUnit 4 möglich eine Basisklasse für alle von der Datenbank abhängigen Tests zu benutzen, die diese Aufgabe übernimmt: ...

October 5, 2008 · updated April 30, 2021 · 2 min

Eclipse-Fangfragen

Eclipse auf amd64 ist ja schon eine Herausforderung. Egal was man tut, es stürzt ständig ab. Heute war es mal so gnädig und hat statt eines Absturzes eine äußerst sinnvolle Frage gestellt: Wer hat schon gerne Probleme? Zumindest auf meinem Rechner reproduzierbar beim Kopieren einer HTML-Datei im Package-Explorer in die Zwischenablage.

September 23, 2008 · updated April 30, 2021 · 1 min