Connect with us

Entwicklung & Code

Vorsicht, versteckte Kosten: Wenn Software nur technisch gedacht wird


Es gibt ein Muster, das sich durch viele Lebensbereiche zieht: Wer kurzfristig spart, zahlt in der Regel langfristig drauf. Wer die Inspektion des Autos überspringt, steht irgendwann mit einem kapitalen Motorschaden da. Wer auf die Beratung durch eine Fachkraft verzichtet, macht Fehler, die teurer werden als das eingesparte Honorar. Oder, wie mein Schwiegervater zu sagen pflegt: „Wer das billige Werkzeug kauft, kauft zweimal.“ Dieses Prinzip ist so alt wie das Wirtschaften selbst, und die meisten Menschen würden ihm vermutlich sofort zustimmen.

Weiterlesen nach der Anzeige

In der Softwareentwicklung existiert eine Variante dieses Musters, die erstaunlich selten als solche erkannt wird: der Verzicht auf ein fundiertes fachliches Konzept zu Projektbeginn. In früheren Blogposts habe ich bereits darüber geschrieben, warum so viele Softwareprojekte scheitern, warum der wahre Engpass nie das Coden war und wie ein bewusst verlangsamter Prozess am Ende schneller ans Ziel führt. Heute geht es um eine Frage, die bislang zu kurz kam: Was kostet es eigentlich konkret, wenn die Fachlichkeit übersprungen wird? Und warum wird diese Rechnung in Zeiten von KI nicht besser, sondern schlechter?

Am Beginn eines Softwareprojekts herrscht in der Regel eine verständliche Ungeduld. Das Budget ist bewilligt, das Team steht bereit, die Erwartungen sind hoch. Die Argumentation, die ich in solchen Situationen immer wieder höre, klingt ungefähr so:

„Entwicklung ist teuer und dauert lange. Jeder Tag, an dem nicht programmiert wird, ist ein verlorener Tag. Also müssen wir so schnell wie möglich anfangen.“

Was auf den ersten Blick nach wirtschaftlicher Vernunft klingt, ist bei genauerer Betrachtung das Gegenteil.

Denn „schnell anfangen“ bedeutet in diesem Kontext fast immer, dass man die Phase überspringt, in der man herausfindet, was die Software eigentlich leisten soll. Es wird nicht die Zeit investiert, die Fachlichkeit zu erarbeiten, die Prozesse zu verstehen, die Anforderungen zu hinterfragen. Stattdessen wird sofort mit der technischen Umsetzung begonnen, weil das nach Fortschritt aussieht. Code entsteht, Commits füllen das Repository, Tickets werden abgearbeitet. Alles wirkt produktiv. Aber Produktivität und Fortschritt sind nicht dasselbe.

Fachlichkeit wird in dieser Logik nicht als Investition verstanden, sondern als Bremse. Als etwas, das die Umsetzung verzögert und das man im Laufe des Projekts nebenbei mitnehmen kann. Ich habe diesen Irrtum in unzähligen Projekten beobachtet, und er ist einer der teuersten, den ein Unternehmen begehen kann. Denn wie ich bereits an anderer Stelle argumentiert habe: Der wahre Engpass in der Softwareentwicklung war nie die Geschwindigkeit, mit der Code entsteht. Er war immer die Geschwindigkeit, mit der Verständnis entsteht. Wer das Verstehen überspringt, um schneller zu bauen, baut nicht schneller. Er baut nur früher das Falsche.

Weiterlesen nach der Anzeige

Wenn die Fachlichkeit nicht systematisch erarbeitet wird, entsteht kein Vakuum. Es entsteht etwas Schlimmeres: eine Sammlung impliziter Annahmen, die niemand als solche erkennt. Jede Entwicklerin und jeder Entwickler hat eine Vorstellung davon, was die Software tun soll. Jede Produktmanagerin und jeder Produktmanager hat ein Bild im Kopf. Jede Stakeholderin und jeder Stakeholder hat Erwartungen. Das Problem ist, dass diese Vorstellungen, Bilder und Erwartungen selten deckungsgleich sind.

Zu Beginn fällt das nicht auf. Alle verwenden die mehr oder weniger gleichen Begriffe und nicken regelmäßig einvernehmlich. Doch unter der Oberfläche verbergen sich unterschiedliche Interpretationen, die erst sichtbar werden, wenn Code existiert und jemand feststellt, dass das Ergebnis nicht dem entspricht, was sie oder er sich vorgestellt hat.

Ein Beispiel aus der Praxis: Ein Team entwickelt eine Software für die Auftragsabwicklung. Alle reden von „Bestellungen“, aber niemand klärt, was eine Bestellung im fachlichen Sinne eigentlich ist. Für die eine Abteilung ist eine Bestellung ein verbindlicher Kaufvertrag, für die andere ein unverbindlicher Wunschzettel, der erst durch eine Freigabe zum Auftrag wird. Das Entwicklungsteam implementiert eine dritte Variante, die keiner der beiden Sichtweisen entspricht. Erst Monate oder im schlimmsten Fall Jahre später, beim ersten Test mit echten Anwenderinnen und Anwendern, bricht das Ganze zusammen. Die Architektur trägt die tatsächliche Komplexität nicht, weil sie auf einem Verständnis aufgebaut wurde, das niemand überprüft hat.

Dann ist die Überraschung groß, und dann beginnt die Suche nach dem Schuldigen. Aber es gibt keinen Schuldigen. Es gibt nur das Fehlen eines gemeinsamen Verständnisses.

Diese impliziten Annahmen werden in Code gegossen und damit zementiert. Jede Architekturentscheidung, jede Datenstruktur, jede Schnittstelle spiegelt das Verständnis wider, das zum Zeitpunkt der Implementierung vorhanden war. War dieses Verständnis lückenhaft oder falsch, ist es die Software auch. Und je mehr Code auf einem falschen Fundament aufbaut, desto schwieriger wird es, die Richtung zu korrigieren. Ich habe dieses Phänomen bereits in einem Blogpost darüber, dass 75 Prozent aller Softwareprojekte scheitern, ausführlich beschrieben. Die Ursache ist fast nie technischer Natur. Sie liegt in der Kluft zwischen dem, was gebaut wurde, und dem, was gebraucht wird.

An dieser Stelle wird es ökonomisch interessant. Denn die Kosten, die durch fehlende Fachlichkeit entstehen, sind zum größten Teil unsichtbar. Was Unternehmen sehen, sind Budgetüberschreitungen und Verzögerungen. Was sie nicht sehen, ist ungleich teurer.

Da ist zunächst die Software, die am Zweck vorbeigeht. Sie funktioniert, sie macht etwas – aber sie löst nicht das Problem, für das sie gebaut wurde. Sie bildet Prozesse ab, die so in der Realität nicht existieren, oder sie bildet sie so ab, dass die Anwenderinnen und Anwender sie umständlich in ihren Alltag integrieren müssen, anstatt von ihnen unterstützt zu werden. Der wirtschaftliche Schaden, der dadurch entsteht, taucht in keiner Projektbilanz auf. Er verteilt sich über Jahre, in Form von Ineffizienz, Workarounds und verpassten Chancen.

Da ist die Nacharbeit, die nicht als Nacharbeit erkannt wird. Wenn ein Team Features überarbeitet, die auf falschen Annahmen basierten, wird das im Backlog als Weiterentwicklung geführt, nicht als Korrektur eines Versäumnisses. Die Stunden fließen in Bugfixes, in Anpassungen, in jene unzähligen kleinen Änderungen, die notwendig werden, weil die ursprüngliche Konzeption nicht tragfähig war. Niemand aggregiert diese Stunden und fragt:

„Wie viel davon wäre vermeidbar gewesen, wenn wir am Anfang zwei Wochen in die Fachlichkeit investiert hätten?“

Und da sind die Architekturentscheidungen, die auf einem falschen Verständnis der Domäne basieren. Eine Datenstruktur, die am tatsächlichen Geschäftsprozess vorbeigeht. Eine Trennung von Modulen, die fachlich zusammengehören. Eine Vereinfachung, die einen Sonderfall ignoriert, der sich später als der Regelfall herausstellt. Solche Entscheidungen lassen sich nachträglich entweder nur mit enormem Aufwand korrigieren oder, was häufiger vorkommt, gar nicht mehr. Sie werden zum Bestandteil der Software, und alles, was darauf aufbaut, erbt ihre Schieflage.

In Slow is smooth and smooth is fast habe ich beschrieben, wie ein bewusst verlangsamtes Vorgehen genau diese Korrekturschleifen eliminiert. Was dort an Nacharbeit wegfiel, fällt in den meisten Projekten eben nicht weg. Und das hat einen Preis, der sich über die gesamte Lebensdauer der Software akkumuliert.

Die eigentliche Tragik besteht darin, dass diese versteckten Kosten selten jemand aufaddiert. Es gibt keine Zeile im Budget, die „Kosten durch fehlendes fachliches Verständnis“ heißt. Stattdessen verteilen sie sich auf hunderte Tickets, auf Dutzende Meetings, auf unzählige Stunden, in denen kluge Menschen Probleme lösen, die bei einem besseren Fundament gar nicht erst entstanden wären. Die Rechnung wird nie gestellt, also wird sie auch nie bezahlt. Zumindest nicht bewusst.

In diese Situation hinein trifft nun das Versprechen der KI-gestützten Softwareentwicklung. Die Verheißung klingt verlockend: weniger Entwicklerinnen und Entwickler, schnellere Umsetzung, niedrigere Kosten. KI-Tools generieren Code in Sekunden, der früher Stunden gedauert hätte. Ganze Prototypen entstehen über Nacht. Die Botschaft, die viele Entscheiderinnen und Entscheider daraus ableiten, lautet: Softwareentwicklung wird billiger und schneller. Also können wir mit weniger Aufwand mehr erreichen.

Das stimmt, aber nur unter einer Voraussetzung: Man muss wissen, was man bauen will. Und genau hier liegt das Problem. KI beschleunigt die Umsetzung, aber sie ersetzt nicht das Verstehen. Eine KI kann beeindruckend schnell Code produzieren, aber sie kann nicht wissen, ob dieser Code das richtige Problem löst. Sie kann eine Schnittstelle implementieren, aber nicht beurteilen, ob diese Schnittstelle den tatsächlichen Geschäftsprozess sinnvoll abbildet. Sie kann Tests generieren, aber nicht entscheiden, welche fachlichen Szenarien wirklich kritisch sind.

Wer nicht weiß, was gebraucht wird, produziert mit KI lediglich schneller Code, der am Ziel vorbeigeht. Man erhält in kürzerer Zeit mehr Software, die nicht das tut, was sie tun sollte. Das ist keine Produktivitätssteigerung. Das ist eine Beschleunigung der Wertvernichtung.

Das Muster ist dabei nicht neu. Dieselbe Verheißung gab es bereits bei Low-Code- und No-Code-Plattformen, bei RAD-Systemen, bei CASE-Tools: Jede Generation hatte ihre Technologie, die das Programmieren so einfach und schnell machen sollte, dass der Engpass verschwindet. Keine dieser Technologien hat das fundamentale Problem gelöst, weil keine von ihnen das Verstehen automatisieren konnte. KI ist leistungsfähiger als alles, was davor kam, aber auch sie kann nicht wissen, was ein Unternehmen braucht, wenn es das selbst nicht weiß.

Doch es kommt noch ein zweiter Effekt hinzu, der vielleicht noch gefährlicher ist: Die scheinbare Kostenersparnis durch KI senkt die Hemmschwelle, ohne fachliches Konzept loszulegen. Wenn Code fast nichts mehr kostet, warum dann Zeit mit der Konzeption verbringen? Wenn ein Prototyp in einem Nachmittag entsteht, warum vorher wochenlang die Fachlichkeit durchdringen? Die Argumentation klingt bestechend, aber sie übersieht, dass die Kosten der Software nur zu einem kleinen Teil im Schreiben des Codes liegen. Der weitaus größere Anteil entfällt auf alles, was danach kommt: Wartung, Anpassung, Korrektur, Integration, Schulung, Betrieb.

KI verändert also die Kostenstruktur der Codeerzeugung, aber nicht die Kostenstruktur der Softwareentwicklung als Ganzes. Und sie verschiebt den Fokus noch weiter in Richtung Technologie und noch weiter weg von der Fachlichkeit. Das ist das Gegenteil dessen, was notwendig wäre. Die versteckten Kosten werden nicht kleiner, sie werden größer. Nur fällt das nicht auf, weil die sichtbare Seite der Rechnung so viel günstiger aussieht.


the next big thing – Golo Roden

the next big thing – Golo Roden

Golo Roden ist Gründer und CTO von the native web GmbH. Er beschäftigt sich mit der Konzeption und Entwicklung von Web- und Cloud-Anwendungen sowie -APIs, mit einem Schwerpunkt auf Event-getriebenen und Service-basierten verteilten Architekturen. Sein Leitsatz lautet, dass Softwareentwicklung kein Selbstzweck ist, sondern immer einer zugrundeliegenden Fachlichkeit folgen muss.

Es gibt eine Parallele, die das verdeutlicht: Stellen Sie sich vor, jemand baut Häuser und bekommt plötzlich ein Werkzeug, mit dem er Wände zehnmal schneller hochziehen kann. Großartig, wenn der Bauplan stimmt. Aber wenn der Bauplan falsch ist, entstehen jetzt einfach nur schneller Häuser, die am Bedarf der Bewohnerinnen und Bewohner vorbeigehen. Der Abriss und Neubau wird nicht billiger, nur weil das Mauern schneller ging. Im Gegenteil: Weil das Bauen so billig erscheint, wird häufiger ohne Plan losgelegt, und die Gesamtkosten steigen.

Meine Argumentation lässt sich unterm Strich auf eine einfache Formel bringen: Fachlichkeit am Anfang eines Projekts ist kein Kostenfaktor. Sie ist eine Investition mit einem messbaren, wenn auch selten gemessenen Return. Jeder Tag, der in das Verstehen der Domäne fließt, in das Hinterfragen von Annahmen, in den Aufbau eines gemeinsamen Verständnisses, spart am Ende ein Vielfaches an Korrektur, Nacharbeit und verfehlter Software.

Das ist keine abstrakte Behauptung. Es ist die Quintessenz aus zahllosen Projekten, die ich in über zwei Jahrzehnten erlebt und begleitet habe. Die Projekte, die am Anfang in Fachlichkeit investiert haben, kamen am Ende schneller ans Ziel, kosteten weniger und lieferten bessere Ergebnisse. Die Projekte, die sofort losgelegt haben, waren schneller am Start, aber langsamer am Ziel. Oft erreichten sie das Ziel gar nicht, zumindest nicht das ursprünglich beabsichtigte.

Das Paradoxe daran: Die Investition in Fachlichkeit muss gar nicht groß sein. Oft genügen wenige Tage intensiver Gespräche mit den richtigen Menschen, um die grundlegenden Missverständnisse aufzudecken, bevor sie im Code landen. Oft reicht es, die eine entscheidende Frage zu stellen, die bislang niemand gestellt hat. Der Aufwand dafür ist verschwindend gering im Vergleich zu dem, was ein Unternehmen für die Korrektur zahlt, wenn diese Frage erst nach Monaten der Entwicklung auftaucht. Es ist, um zum Eingangsbild zurückzukehren, der Unterschied zwischen der Inspektion, die ein paar hundert Euro kostet, und dem Motorschaden, der in die Tausende geht.

Der eigentliche Engpass in der Softwareentwicklung war nie die Geschwindigkeit der Umsetzung. Er war und ist das Verständnis dessen, was überhaupt gebaut werden soll. Solange dieses Verständnis fehlt, macht schnellere Technologie nichts besser. Sie macht nur das Falsche schneller. KI ist dafür ein eindrucksvolles Beispiel, aber bei Weitem nicht das Erste.

Die versteckten Kosten fehlender Fachlichkeit werden erst sichtbar, wenn man beginnt, die Rechnung ehrlich aufzumachen. Wenn man fragt: Wie viel unserer Entwicklungszeit fließt in die Korrektur von Missverständnissen? Wie viel unserer Software löst tatsächlich das Problem, für das sie gedacht war? Wie viel unserer Architekturentscheidungen basieren auf einem fundierten Verständnis der Domäne und wie viele auf Vermutungen?

Wer sich diese Fragen stellt, wird feststellen, dass die Antworten unbequem sind. Aber sie sind der erste Schritt, um die teuerste Fehlentscheidung in der Softwareentwicklung zu vermeiden: den Verzicht auf das Fundament, auf dem alles andere steht.


(rme)



Source link

Entwicklung & Code

WTF: Microsoft erzwingt „Co-Authored-by Copilot“ in Commits


Ein Pull Request für VS Code sorgt auf Github derzeit für Unmut: Denn er macht Copilot standardmäßig zum Co-Autor in jeder Commit Message, sofern das KI-Tool bei den jeweiligen Änderungen an einem Projekt mithilfe der Programmiersoftware VS Code zum Einsatz kam. In der Developer-Community herrschte neben Verwirrung über das Thema auch einiger Frust über diesen Schritt. Wer sich die Commit Message nicht mit Copilot teilen will, kann diese Einstellung aber deaktivieren.

Weiterlesen nach der Anzeige

Laut der Übersicht zum Pull Request wird die Einstellung git.addAICoAuthor der Git-Erweiterung für VS Code standardmäßig auf all gesetzt. Die Auswirkung: Wenn bei einer Änderung am Code ein Copilot-Feature genutzt wird, etwa Inline-Vervollständigungen oder Agenteneinsatz, wird dieses bei der Veröffentlichung auf Git in der Commit Message kenntlich gemacht. Hier ist dann „Co-authored-by: Copilot copilot@github.com“ zu lesen.

In der Community sorgte das zunächst für einige Verwirrung, mancher Nutzer versuchte verzweifelt, die Copilot-Erwähnung händisch wieder aus der Commit Message zu löschen – nur um diese dann nach Veröffentlichung darin wiederzufinden, wie jemand in diesem Git-Thread berichtet. Unter dem Pull Request selbst häufen sich derweil Beschwerden aus der Nutzerschaft. Viele ärgern sich über mangelndne Kommunikation der Änderung und berichten ebenfalls vom zunächst unerklärlichen Verhalten der Commit Messages. Aber es gibt offenbar auch größere Probleme: Mehrere Nutzer beklagen, dass Copilot auch dann erwähnt wird, wenn das Tool überhaupt nicht zum Einsatz kam.

Über die Einstellungen von VS Code lässt sich das neue Verhalten deaktivieren. Über das Zahnrad unten links gelangt man ins entsprechende Menü. Hier muss unter Settings>Extensions>Git unter „Add AI Co Author“ die Option „off“ gesetzt werden. Alternativ kann auch "git.addAICoAuthor": "off" in der settings.json eingetragen werden.

Bei einem kurzen Test in unserer Redaktion mit VS Code v1.118 unter macOS war in den VS-Code-Einstellungen standardmäßig „chatAndAgent“ gesetzt. Laut Microsoft soll sich die automatische Copilot-Erwähnung damit auf Fälle beschränken, in denen Hilfestellungen des Chatbots oder des KI-Agenten genutzt wurden. Wer sichergehen will, sollte aber auf jeden Fall die Einstellung „off“ wählen.

Weiterlesen nach der Anzeige

Lesen Sie auch


(nen)



Source link

Weiterlesen

Entwicklung & Code

Assertion Libraries für Java: AssertJ versus Google Truth


close notice

This article is also available in
English.

It was translated with technical assistance and editorially reviewed before publication.

Unit Tests sind ein fundamentales Element im Software Engineering. Sie garantieren die funktionale Korrektheit der Software und helfen dabei, potenzielle Fehler frühzeitig zu identifizieren. Assertions (Behauptungen) spielen dabei eine zentrale Rolle, indem sie sicherstellen, dass die erwarteten Bedingungen während der Testausführung erfüllt sind.

Weiterlesen nach der Anzeige


Marco Dahms

Marco Dahms

Marco Dahms ist seit 18 Jahren als Softwarearchitekt tätig. Seine Tätigkeitsschwerpunkte liegen in den Bereichen Clean Code, Continuous Integration, Cloud Computing, verteilte Architekturen und Kubernetes.

Unit Tests enthalten Assertions, die das verwendete Testframework zum Testzeitpunkt auf Einhaltung prüft. Ein einfaches Beispiel ist die Prüfung, ob der Rückgabewert einer bestimmten Methode true lautet. Falls eine Assertion nicht zutrifft, bricht der Test die Ausführung ab und gilt als fehlgeschlagen. Wenn alle Assertions eingehalten werden, führt das Testframework den Test bis zum Ende aus und dieser gilt als erfolgreich.

Ein Unit Test kann mehrere Assertions enthalten, wobei sie sich typischerweise am Ende der Testmethode befinden. In seltenen Fällen ist es möglich, dass Assertions in der Mitte des Testfalls geprüft werden, um die Einhaltung von Zwischenbedingungen für den Test sicherzustellen.

Für die Formulierung von Assertions in der jeweiligen Programmiersprache kommt in der Regel die API des Testframeworks zum Einsatz. So bietet etwa JUnit für Java einfache APIs an, um Assertions auszudrücken.

Sie reichen in der Regel für einfache Tests mit wenigen Assertions aus und haben den Vorteil, dass sie direkt im Testframework verfügbar sind. Daher muss man keine zusätzlichen Dependencies in das Softwareprojekt einbinden.


Aufmacher bcc Testing

Aufmacher bcc Testing

(Bild: laolina / 123rf.com)

Die betterCode() Testing 2026 zeigt am 8. Juni 2026, wie das Zusammenspiel von Mensch, Tools und Prozessen den Erfolg moderner Software sichert. Im Fokus stehen Testing mit und von KI, Testautomatisierung und Praxisberichte, die zeigen, was wirklich getestet werden sollte.

Ist das Projekt jedoch umfangreicher und sind die Tests aufwendiger, stoßen diese APIs an ihre Grenzen. Zunächst sind sie nicht auf Lesbarkeit und Verständlichkeit optimiert. Für kompliziertere Assertions müssen Entwicklerinnen und Entwickler viel Boilerplate-Code schreiben. Darüber hinaus sind die Fehlermeldungen bei nicht eingehaltenen Assertions eher kurz und abstrakt und lassen relevante Details zur Fehlersuche vermissen, beispielsweise über fehlende Elemente in einer Collection. Weiterhin ist die Assertion API von JUnit nicht erweiterbar, lässt sich also nicht um Assertions für die eigene Domänenlogik ergänzen.

Weiterlesen nach der Anzeige

Das folgende Listing zeigt ein Beispiel, das die Einschränkungen der JUnit Assertion API demonstriert.


  @Test
  public void testListComparison() {
    List expectedList = Arrays.asList("Apple", "Banana", "Cherry");
    List actualList = Arrays.asList("Apple", "Grape", "Cherry");

    assertEquals(expectedList, actualList, "Die Listen sollten gleich sein");
  }


Zunächst werden zwei Listen, die Strings enthalten, erzeugt. Der Aufruf der Methode assertEquals verlangt, dass die beiden Listen gleich sein sollen. Da die Listen unterschiedliche Elemente enthalten, schlägt der Test mit folgender Meldung fehl:

Die Listen sollten gleich sein ==> expected: <[Apple, Banana, Cherry]> but was: <[Apple, Grape, Cherry]>

Die Meldung verdeutlicht nicht, welche Elemente in den Listen unterschiedlich sind. In diesem stark vereinfachten Beispiel mag das für Developer leicht erkennbar sein, in der Praxis ergeben sich hingegen oft komplexere Fälle. Es wäre hilfreich, wenn die Meldung die konkrete Information enthält, welche Elemente unterschiedlich sind. In diesem Fall: die Strings Banana und Grape.

Eine weitere Assertion könnte darin bestehen, dass ein konkretes Element exakt einmal in einer Liste vorkommt. Mit der API von JUnit lässt sich diese Anforderung nicht unmittelbar umsetzen. Entwickler müssen den dafür notwendigen Code selbst schreiben. Assertion Libraries wie AssertJ oder Google Truth besitzen solche Einschränkungen nicht. Die APIs der beiden Libraries sind auf Lesbarkeit und Verständlichkeit optimiert. Ihre Assertions lesen sich in der Regel wie natürliche Sprache. Insbesondere lassen sich mehrere Assertions in einem Ausdruck verketten, was Boilerplate-Code verringert.

Fehlermeldungen bei verletzten Assertions sind bedeutend detaillierter, und erleichtern die Fehlersuche. Daneben gibt es umfangreiche spezialisierte APIs für die Standardtypen in Java, etwa Strings, Listen oder Exceptions.

AssertJ ist eine quelloffene Java-Bibliothek mit einer umfangreichen Menge an Assertions und hilfreichen Fehlermeldungen. Sie hat vor allem das Ziel, die Lesbarkeit von Testcode zu verbessern. AssertJ Core ist der Kern von AssertJ, daneben gibt es weitere AssertJ-Module für Bibliotheken wie Guava.

Die Library lässt sich als org.assertj:assertj-core über Maven und Gradle in ein Java-Projekt einbinden. Ein Projekt mit Spring Boot verwaltet die AssertJ-Version automatisch. Falls es notwendig ist, lässt sich die AssertJ-Version mit der Property assertj.version überschreiben.

AssertJ bietet eine große Auswahl an verschiedenen Assertion APIs für eine Vielzahl an Java-Standardtypen, darunter gängige Typen wie String, List oder Predicate und primitive Typen wie int oder char. Diese APIs sind auf den jeweiligen Typen spezialisiert und bieten Methoden an, die dabei helfen, das Schreiben von Boilerplate-Code zu vermeiden. Es folgt eine Übersicht:

String-APIs:

  • isNotBlank: String ist kein Leerstring
  • contains: String enthält einen Substring
  • hasSize: String hat eine bestimmte Länge
  • isUpperCase: String umfasst nur Großbuchstaben

Listen-/Iterable-APIs:

  • contains: Liste enthält Elemente in beliebiger Reihenfolge
  • containsOnly: Liste enthält nur bestimmte Elemente in beliebiger Reihenfolge
  • containsExactly: Liste enthält nur bestimmte Elemente in gegebener Reihenfolge

Die Vielfalt an Assertions deckt somit viele Anwendungsfälle ab.

Entwicklerinnen und Entwickler können Assertions mit zusätzlicher Semantik versehen, indem sie eine textuelle Beschreibung beim Aufruf mitgeben. Diese ist wiederum Teil der Fehlermeldung, sofern die Assertions nicht eingehalten werden. Über eine Konfiguration lässt sich steuern, ob diese Beschreibungen direkt auf der Standardkonsole ausgegeben oder durch eine eigene Logik in einem sogenannten Description Consumer konsumiert werden sollen, um sie beispielsweise in einer Datei zu speichern.

Der Einstiegspunkt für Developer sind die Assertions-Klasse und die darin enthaltenen Methoden assertThat(…). Die Namensgebung assertThat(…) zeigt, dass Wert auf die Intuitivität und Lesbarkeit der Assertions gelegt wird. Die Assertions lesen sich dadurch wie natürliche Sprache. Zunächst wird assertThat als statischer Import deklariert:

import static org.assertj.core.api.Assertions.assertThat;

Als Nächstes kann man in einer Testmethode assertThat(foo). schreiben, wobei foo sich auf den Wert oder das Objekt bezieht, auf dem die Assertion beruht. Je nachdem, was foo für einen Typ hat, bieten IDEs bei richtig konfigurierter Codevervollständigung die passenden Assertion-APIs an. Übergibt man beispielsweise ein Objekt vom Typ LocalDate als Argument, erhält man Empfehlungen wie hasMonth oder isAfter. Daraus ergibt sich etwa folgende Zusammenstellung der Assertion:

assertThat(date).isNotNull().hasMonth(Month.of(1)).isAfter(beginDate);

Die Assertion lässt sich nun in natürlicher Sprache so lesen: „Stelle sicher, dass date nicht null ist, den Monat 1 (Januar) hat und nach einem anderen Datum beginDate fällt“. Die Verkettung der Methodenaufrufe vermeidet Boilerplate-Code und erhöht die Lesbarkeit. Sobald eine der Assertions fehlschlägt, werden die nachfolgenden nicht mehr überprüft.

Wenn Entwickler alle Assertions prüfen lassen möchten, bevor ein Test abbricht, verwenden sie SoftAssertions. Dafür erzeugen sie ein Objekt vom Typ SoftAssertions, rufen darauf die gewünschten Assertion-Methoden auf und lösen am Ende mit assertAll die finale Überprüfung aus. AssertJ stellt anschließend eine Übersicht aller fehlgeschlagenen Assertions zusammen. Dieser Ansatz eignet sich besonders für komplexe Testfälle, da er einen direkten Überblick über alle Fehler liefert und verhindert, dass der Test nach jeder Fehlerbehebung erneut gestartet werden muss.

Darüber hinaus lässt sich AssertJ um Assertions für die eigene Anwendungsdomäne erweitern. Das Schreiben von Custom Assertions erlaubt das Entwickeln von Assertion-Methoden, die auf das eigene Datenmodell zugeschnitten sind. Im Falle einer Terminverwaltungssoftware könnte man sich etwa folgende Assertions überlegen:

  • assertThat(appointment).isDue()
  • assertThat(appointment).isCancelled()

Appointment wäre eine Klasse aus dem eigenen Domänenmodell und isDue sowie isCancelled wären selbst entwickelte Assertion-Methoden. Dieses Vorgehen erhöht die Lesbarkeit sowie die Verständlichkeit von Unit Tests, indem sich die eigene Anwendungsdomäne aus dem Produktivcode auch in den Tests widerspiegelt. Um eine Custom Assertion umzusetzen, müssen Entwicklerinnen und Entwickler eine neue Klasse von der abstrakten Klasse AbstractAssert ableiten, einen Konstruktor und eine statische assertThat-Methode und weiterhin alle erforderlichen Assertion-Methoden (wie isDue, isCancelled usw.) implementieren.

Eine weitere Assertion Library für Java ist Google Truth, entwickelt und gewartet von Googles Guava-Team. Sie kommt in der Mehrheit aller Tests in der Google-Codebasis zum Einsatz. Der inhaltliche Fokus liegt auf lesbaren Assertions und Fehlermeldungen. Truth unterstützt viele Java-Standardtypen und Typen aus der Guava-Library. Die Einbindung von Truth in Maven- oder Gradle-Projekte erfolgt über das Artefakt com.google.truth:truth.

Um Truth in einem Test einzusetzen, braucht es zunächst die Methode assertThat, bereitgestellt über einen statischen Import:

import static com.google.common.truth.Truth.assertThat;

Ähnlich wie bei AssertJ lässt sich ein Objekt als Argument an assertThat übergeben, woraufhin sich des Typen des Arguments entsprechende Assertion-APIs ergeben. Ein einfaches Beispiel aus der Truth-Dokumentation ist der Check, ob ein String mit einem bestimmten Teilstring beginnt:


String string = "awesome";
assertThat(string).startsWith("awe");


Um den Fehlermeldungen bei verletzten Assertions mehr Semantik zu verleihen, können Entwicklerinnen und Entwickler eine passende Beschreibung mitgeben. Dazu importieren sie die Methode assertWithMessage und rufen sie auf:


import static com.google.common.truth.Truth.assertWithMessage;

assertWithMessage("Without me, it's just aweso")
    .that(string)
    .contains("me");


Auch Truth erlaubt das Erweitern um eigene Custom Assertions. Im Truth-Datenmodell schreibt man dafür ein eigenes Custom Subject. Die eigene Subject-Klasse muss von der Klasse Subject abgeleitet sein. Zusätzlich braucht es eine statische Hilfsmethode und einen Konstruktor. Außerdem mussen spezifische Assertion-Methoden ergänzt werden. Die Truth-Dokumentation verweist auf das Referenzbeispiel des EmployeeSubject.

Bei umfangreichen Tests mit vielen Assertions, bei denen eine vollständige Überprüfung aller Assertions hilfreich ist, kommt in Truth die Klasse Expect zum Einsatz, initialisiert über eine JUnit-Rule-Annotation:

@Rule public final Expect expect = Expect.create();

Auf dem Objekt Expect kann man dann ähnlich wie bei assertThat ein Argument übergeben und passende Assertions formulieren. Leider zeigt sich, dass dieser Ansatz nur bis JUnit 4 unterstützt wird. Ab JUnit 5 ist die Rule-Annotation nicht mehr möglich und Truth bietet bisher (Stand April 2026) keine alternative Implementierung dafür an. Da im September 2025 JUnit 6 erschienen ist, ist die Verwendung von JUnit 4 nicht zu empfehlen. Folglich lässt sich Expect nicht mehr sinnvoll einsetzen.



Source link

Weiterlesen

Entwicklung & Code

Neu in .NET 10.0 [21]: Ausgabe der Befehle und Parameter in JSON bei SDK-Tools


close notice

This article is also available in
English.

It was translated with technical assistance and editorially reviewed before publication.

Mit dem neuen Parameter --cli-schema erhalten Entwicklerinnen und Entwickler seit .NET 10.0 bei den .NET-SDK-Kommandozeilenbefehlen eine Ausgabe der Befehlsoptionen und Parameter in JavaScriot Object Notation (JSON).

Weiterlesen nach der Anzeige


Der Dotnet-Doktor – Holger Schwichtenberg

Der Dotnet-Doktor – Holger Schwichtenberg

Dr. Holger Schwichtenberg ist technischer Leiter des Expertennetzwerks www.IT-Visions.de, das mit 53 renommierten Experten zahlreiche mittlere und große Unternehmen durch Beratungen und Schulungen sowie bei der Softwareentwicklung unterstützt. Durch seine Auftritte auf zahlreichen nationalen und internationalen Fachkonferenzen sowie mehr als 90 Fachbücher und mehr als 1500 Fachartikel gehört Holger Schwichtenberg zu den bekanntesten Experten für .NET und Webtechniken in Deutschland.

Zuvor waren diese Informationen bereits in reiner Textform über die Hilfefunktion abrufbar, allerdings durch mehrere Einzelbefehle, wie beispielsweise

dotnet package -h
dotnet package add -h
dotnet package list -h


Screenshot

Screenshot

Der Screenshot zeigt einen Ausschnitt aus der Ausgabe des JSON-Schemas eines .NET-SDK-CLI-Befehls (Abb. 1).


Screenshot

Screenshot

Der Screenshot zeigt einen Ausschnitt der Hilfeinformationen eines .NET-SDK-CLI-Befehls (Abb. 2).


(rme)



Source link

Weiterlesen

Beliebt