5 Software testen
Testwerkzeuge und -frameworks haben sich in der Softwareentwicklung etabliert und zählen zum Standard, wenn es um Qualitätssicherung geht. Testing umfasst weit mehr als nur das klassische Unittesten. Es beginnt bei der Erzeugung sinnvoller Testdaten für die Entwicklung und manuelle Tests, über die Absicherung einzelner Codeblöcke und reicht bis hin zum Ende-zu-Ende-Testing. Jede dieser Testarten stellt ihre eigenen Herausforderungen und erfordert spezifische Ansätze und Werkzeuge. In jedem Bereich können Sie auf verschiedene KI-Werkzeuge zurückgreifen und sich teilweise viel Arbeit abnehmen lassen.
Eines haben Softwaretests jedoch gemeinsam: Sie wiederholen sich häufig, da ein Grundstock an Testmustern immer wieder verwendet wird. Deshalb zählt das Schreiben von Tests nicht zu den Lieblingsaufgaben von Softwareentwicklern und hat oft den Ruf, unnötig viel Zeit in Anspruch zu nehmen und Ressourcen zu binden, die eigentlich für die Feature-Entwicklung genutzt werden könnten. Gerade hier können KI-Werkzeuge eine entscheidende Rolle spielen, indem sie repetitive Aufgaben effizient übernehmen und den Testaufwand erheblich reduzieren.
Der Einsatz von KI-Werkzeugen ist nicht auf eine bestimmte Ebene von Tests beschränkt, sondern kann als Hilfsmittel überall eingesetzt werden. Mit richtig formulierten Prompts und dem passenden Kontext können die KI-Werkzeuge bereits viele Testfälle automatisch abdecken. Diese Unterstützung reduziert nicht nur den Zeitaufwand, sondern kann auch Testfälle erkennen, an die Entwickler möglicherweise nicht gedacht haben. Zudem kann KI eine »zweite Meinung« oder andere Sichtweisen beisteuern, was die Tests insgesamt besser und robuster macht.
In der testgetriebenen sowie in der testbegleitenden Entwicklung kann KI entscheidend zur Testautomatisierung beitragen und für eine umfassende Testabdeckung sorgen. Trotz der vielen Vorteile gibt es jedoch auch Herausforderungen. Die KI hat nicht immer recht und kann teilweise gerade durch Halluzinationen falsche Informationen generieren. Deshalb ist es wichtig, dass Sie die von KI generierten Tests stets überprüfen und zumindest einer Plausibilitätsprüfung unterziehen. Schließlich geht es um die Absicherung der Software, und hier dürfen Sie kein Risiko eingehen.
In Zukunft wird KI eine noch größere Rolle im Softwaretesten spielen. Sie kann Ihnen viel Arbeit abnehmen und es Ihnen ermöglichen, sich auf die eigentliche Entwicklung zu konzentrieren. Dennoch bleibt sie ein Werkzeug, das – wie jedes andere Werkzeug auch – richtig eingesetzt und überwacht werden muss. Die Kombination aus menschlichem Know-how und der Effizienz von KI verspricht, das Softwaretesten auf ein neues Level zu heben und die Qualität von Softwareprodukten nachhaltig zu verbessern.
5.1 Erzeugen von Testdaten
Während der Entwicklung haben Sie immer mit Daten zu tun, sei es bei einem Formular für die Registrierung neuer Nutzer, einer Listenanzeige von Kundendaten oder einer Validierungsfunktion für eine IBAN. Im Idealfall nutzen Sie schon während der Entwicklung realitätsnahe Daten. Genau an dieser Stelle beginnen die Probleme: Wie sollen realistische Daten aussehen und woher stammen die Daten? Als konkretes Beispiel für diesen Fall dient uns die Implementierung der Kundenliste, wie sie häufig im E-Commerce-Bereich vorkommt. Die Kundenliste soll als einfache HTML-Tabelle umgesetzt werden, die mithilfe von TypeScript aufgebaut wird. Typdefinitionen sind bei der Arbeit mit KI immer hilfreich, da Sie mit ihnen die Struktur vorgeben können, für die Ihnen die KI Daten generieren soll. Schon bei der Generierung solcher Typen können Sie sich helfen lassen, indem Sie die grobe Struktur vorgeben und die KI die Details übernehmen lassen.
Prompt: Please create a TypeScript alias Customer with the following fields: id, first name, last name, email, registration date, status and last order date.
Sure! Here is how you can create a TypeScript type alias named Customer with the specified fields:
type Customer = {
id: string;
firstName: string;
lastName: string;
email: string;
registrationDate: Date;
// Assuming status is one of these values
status: 'active' | 'inactive' | 'suspended';
// Assuming lastOrderDate can be null if there's no order
lastOrderDate: Date | null;
};
Here’s a brief explanation of each field:
… explanation of the fields …
Der generierte Code folgt genau den Anweisungen des Prompts. Bei Feldern, die nicht eindeutig sind, wie status und lastOrderDate, wurde ein Kommentar mit der entsprechenden Annahme eingefügt. status ist ein Union-Type mit drei Werten, und bei lastOrderDate kann entweder ein Datumswert oder null eingesetzt werden. Sie können den Prompt noch weiter einschränken und bestimmte Typen vorgeben, allerdings verlieren Sie in diesem Fall die Vorteile der KI, da Sie die Struktur schon fast selbst implementieren. Eine Alternative zu einem solchen Prompt kann die Autovervollständigung von Werkzeugen wie GitHub Copilot sein. Beginnen Sie den Customer-Typ zu implementieren, schlägt Ihnen der Copilot Felder und Datentypen vor, die Sie übernehmen können.
Die Implementierung besteht aus zwei Teilen: einer HTML-Datei, die für die Anzeige verantwortlich ist, und einer TypeScript-Datei, die die Daten dynamisch aufbaut. Der Code der HTML-Datei könnte folgendermaßen aussehen:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script type="module" src="list.js"></script>
</head>
<body>
<table>
<thead>
<tr>
<th>Id</th>
<th>First name</th>
<th>Last name</th>
<th>Email</th>
<th>Registration date</th>
<th>status</th>
<th>Last order date</th>
</tr>
</thead>
<tbody></tbody>
</table>
</body>
</html>
Die HTML-Struktur besteht aus dem allgemeinen Rahmen des Dokuments, der Kopf-Sektion, die die JavaScript-Datei zum Aufbau der Tabelle lädt, und dem Body, der das Grundgerüst der Tabelle und ein leeres <tbody>-Element enthält, in das die Daten eingefügt werden.
import type { Customer } from './customer';
const customers: Customer[] = [];
document.addEventListener('DOMContentLoaded', () => {
drawTable(customers);
});
function drawTable(customers: Customer[]) {
const customerTable = customers.map((customer) => {
return `
<tr>
<td>${customer.id}</td>
<td>${customer.firstName}</td>
<td>${customer.lastName}</td>
<td>${customer.email}</td>
<td>
${customer.registrationDate.toISOString()
.split('T')[0]}
</td>
<td>${customer.status}</td>
<td>
${customer.lastOrderDate.toISOString().split('T')[0]}
</td>
</tr>
`;
});
document.querySelector('tbody')!.innerHTML =
customerTable.join('');
}
Was an dieser Stelle noch fehlt, sind die Testdaten. Diese lädt der Browser typischerweise asynchron vom Backend. Der Einfachheit halber gehen wir jedoch davon aus, dass sie bereits in Form der customers-Konstanten vorliegen. Hier können Sie damit beginnen, selbst Daten zu erfinden, Sie können das LLM Ihrer Wahl jedoch auch bitten, Testdaten für Sie zu erzeugen.
Prompt: Please create an array with 10 elements of realistic test data. The data should represent European customers. Ensure that the lastOrderDate is later than the registration Date. Use the following TypeScript type:
type Customer = {
id: string;
firstName: string;
lastName: string;
email: string;
registrationDate: Date;
status: 'active' | 'inactive' | 'suspended';
lastOrderDate: Date | null;
};
Sure! Here is an array with 10 elements of realistic test data for European customers:
const customers: Customer[] = [
{
id: '1',
firstName: 'Anna',
lastName: 'Müller',
email: 'anna.mueller@example.de',
registrationDate: new Date('2022-01-15'),
status: 'active',
lastOrderDate: new Date('2023-04-18'),
},
{
id: '2',
firstName: 'Luca',
lastName: 'Rossi',
email: 'luca.rossi@example.it',
registrationDate: new Date('2021-11-20'),
status: 'active',
lastOrderDate: new Date('2023-02-25'),
},
...
Die Antwort von ChatGPT können Sie direkt in Ihrer Applikation verwenden. Die generierten Daten entsprechen halbwegs realistischen Daten, die nicht nur auf deutsche Datensätze, sondern bunt gemischt aus europäischen Ländern stammen. Die Datumswerte sind ebenfalls korrekt, und auch die Regel, dass das Datum der letzten Bestellung nach dem Datum der Registrierung liegen soll, wurde eingehalten.
Dieses Beispiel zeigt Ihnen, wie Sie sich einige Arbeit bei der Erzeugung von Testdaten abnehmen lassen können. Doch auch hier ist etwas Vorsicht geboten. Je mehr Freiheit Sie dem KI-Werkzeug geben, desto mehr kann es interpretieren. Dass das Datum der Registrierung vor dem Datum der letzten Bestellung liegt, war letztendlich Glück. Die KI hätte hier, ohne weitere Vorgaben, auch die Datumswerte umkehren können. Für die Liste ist das noch kein großes Problem, für die weitere Arbeit mit den Daten, gerade wenn es um Validierungsroutinen geht, kann das schnell zum Problem werden.
Was Sie in einem solchen Fall auch noch beachten sollten, ist die Anzahl der generierten Datensätze. Bei einer niedrigen Zahl wie 10 arbeitet ChatGPT zuverlässig und fehlerfrei. Je mehr Datensätze Sie anfordern, desto größer wird das Risiko, dass sich Duplikate einschleichen, was Sie über Ihren Prompt ausschließen können, oder dass das Werkzeug nach einer gewissen Anzahl an Datensätzen die Arbeit verweigert und entweder mitten in der Datenstruktur abbricht oder etwas wie »hier könnten noch 40 weitere Datensätze folgen« ausgibt. In diesem Fall können Sie sich die Datensätze in kleineren Gruppen erzeugen lassen und sie selbst zusammenfügen.