Large Language Models (LLM) können die Effizienz in Softwareprojekten verbessern. chatgpt hilft nicht nur beim Schreiben von Code, sondern auch beim Erstellen von Softwaretests. Das funktioniert besonders gut, wenn Entwicklungsteams automatisierte Tests benötigen und es wenig fundamentale Abweichung in den Testfällen gibt. Der folgende Text stellt ein Fallbeispiel anhand von Ende-zu-Ende-Tests (E2E) mit dem Testframework Cypress vor.
Anzeige
Softwaretests tragen dazu bei, die Funktionsweise und Zuverlässigkeit einer Anwendung zu gewährleisten. Sie sind ein essenzieller Bestandteil jedes Softwareentwicklungsprojekts. Das Erstellen der Tests ist allerdings potenziell zeitaufwendig und wird daher oft vernachlässigt. Teams müssen nicht nur die Software kontinuierlich warten, sondern die Tests parallel zum Entwicklungsprozess erstellen und aktualisieren. Das erfordert ständige Aufmerksamkeit und damit Zeit und Aufwand auf Entwicklerseite.
Diese Herausforderungen beeinflussen anders als standardisierte Tests ständig das Abwägen von Kosten und Nutzen für die Weiterentwicklung der Anwendung. Kippt das Verhältnis, leidet die Softwarequalität. Es gibt daher immer wieder Projekte, für die es günstiger ist, eine Armada von Testern an das Projekt zu setzen, statt automatisierte Tests zu entwickeln und zu aktualisieren. Je schneller sich das Produkt ändert, desto gravierender wird die Problematik.
Multiplattformfähige Softwareprojekte stellen die beteiligten Entwickler vor zusätzliche Herausforderungen. Gegebenenfalls muss die gleiche Funktion in allen unterstützten Umgebungen getestet werden. Somit multipliziert sich der Aktualisierungsaufwand der Tests mit der Anzahl der Zielplattformen.
Wer beispielsweise an einem Angular-Projekt mit Capacitor arbeitet, das eine Webanwendung in eine native Anwendung verpackt, kann E2E-Tests wahlweise in Cypress, Espresso oder XCTest schreiben. ChatGPT kann beim Schreiben von standardisierten Tests unterstützen und damit Kapazitäten für anspruchsvollere Aufgaben freimachen.
Als leistungsfähiger Textgenerator kann das KI-System Testcodes basierend auf vorhandenen Testfällen oder Anforderungen generieren. Teams können damit
- Zeit und Ressourcen sparen: Statt manuell separate Testcodes für Web, Android und iOS zu schreiben, hilft ChatGPT dabei, Testcode auf der Grundlage vordefinierter Testfälle automatisch zu generieren.
- Konsistenz gewährleisten: Die von dem KI-Modell erstellten Testcodes sind konsistent und decken den gleichen Testfall ab.
- Wartungsaufwand reduzieren: Da ChatGPT den Testcode automatisch generiert, ist es einfacher, die Testfälle zu aktualisieren und die Testcodes auf mehreren Plattformen zu synchronisieren.
ChatGPT gewinnbringend einsetzen
Grundsätzlich lassen sich auch andere LLMs nutzen, aber dieser Artikel setzt beispielhaft auf ChatGPT-4 von OpenAI, weil es sich einfach integrieren lässt und gute Performance bietet. Es gibt auch Fälle, in denen der Einsatz von ChatGPT zum Generieren von Tests nur geringen Nutzen bringt. Es gibt jedoch diverse Szenarien, in denen LLMs helfen können, die Ressourcen in Projekten effizienter einzusetzen:
- Das Projekt benötigt viele Testfälle, die schnell und effizient erstellt werden sollen. Hierbei bauen die Testfälle auf ähnlichen Mustern auf, die sich mit geringer Variation wiederholen.
- Ein Team will den Wartungsaufwand für den Testcode reduzieren und dessen Erstellung vom Entwickeln der eigentlichen Anwendung entkoppeln.
- Eine Projektanwendung läuft auf mehreren Plattformen und für alle Testfälle sollen eigene Tests für jede Plattform laufen.
- Die für das Projekt verfügbaren Ressourcen sind begrenzt. Daher muss das Team den Testcode schnell und effizient erstellen, um Kosten und Zeit zu sparen.
ChatGPT eignet sich besonders gut für Projekte, die viele automatisierte Tests benötigen und bei denen es wenig Abweichung in den Testabläufen gibt. Auf die Weise können Teams das Schreiben von Testcode von der Entwicklung der Anwendung trennen und damit nach dem DRY-Prinzip (Don’t Repeat Yourself) arbeiten.
Noch wichtiger ist, dass der Einsatz von ChatGPT Kapazitäten für die komplexen Herausforderungen freischaufelt und die spezifischen Probleme eines Projekts mehr Aufmerksamkeit erhalten. Für das Projektmanagement entsteht kein zusätzlicher finanzieller Druck, da es bestehende Ressourcen umverteilt und zunächst keine zusätzlichen Ressourcen schaffen muss.
Beispielfall: Cypress-Tests mit ChatGPT
Folgendes Beispiel dreht sich um den Test eines einfachen Angular-Services, der über die öffentliche JSONPlaceholder-API Nutzerdaten abruft.
@Injectable({
providedIn: 'root'
})
export class UserService {
private apiUrl =
'https://jsonplaceholder.typicode.com/users';
constructor(private http: HttpClient) { }
getUsers(): Observable {
return this.http.get(this.apiUrl);
}
getUserById(id: number): Observable {
return this.http.get(`${this.apiUrl}/${id}`);
}
}
Das Objekt UserService
stellt zwei Methoden bereit: getUsers()
ruft alle Nutzer ab und getUserById(id: number)
gibt einen User anhand seiner ID zurück.
Die Angular-Komponente verwendet den Service folgendermaßen:
import { UserService, User } from './user.service';
@Component({
...
})
export class AppComponent implements OnInit {
users: User[] = [];
constructor(private userService: UserService) {}
ngOnInit() {
this.userService.getUsers().subscribe(users => {
this.users = users;
});
}
}
Diese Komponente nutzt die Methode UserService
um alle Nutzerdaten abzurufen und im users
-Array zu speichern. Anschließend werden die Nutzerdaten in der Komponentenvorlage angezeigt:
-
{{ user.name }} ({{ user.email }})
ChatGPT kann für diese Anwendung unterschiedliche Standardtests schreiben. Statt jedoch einfach den vollständig zu testenden Code an ChatGPT zu übergeben, empfiehlt es sich eine Testfalldefinition zu erstellen. Auf diese Weise können Teams die Tests in einer externen Datei speichern, anpassen und erweitern, ohne den ChatGPT-Prompt ändern zu müssen. Das senkt die Kosten und reduziert zusätzlich das Risiko von Datendiebstahl, da nur die Informationen an die ChatGPT-API übertragen werden, die zum Generieren der Tests erforderlich sind.
Der erste Schritt ist, eine JSON-Datei user-service-tests.json
zu erstellen, um die Testfälle für den Angular-Service zu definieren. Sie sollte sowohl die Informationen zu den Methoden des zu testenden Dienstes enthalten als auch eine Beschreibung der erwarteten Ergebnisse.
{
"unitTests": [
{
"description": "getUserById",
"method": "getUserById",
"input": 1,
"output": {
"id": 1,
"name": "John Doe",
"email": "[email protected]"
}
},
{
"description": "getUsers",
"method": "getUsers",
"output": [
{
"id": 1,
"name": "John Doe",
"email": "[email protected]"
},
{
"id": 2,
"name": "Jane Doe",
"email": "[email protected]"
}
]
}
],
"e2eTests": [
{
"description": "Display users list",
"endpoint": "/users",
"expectedElements": [
"#user-1",
"#user-2"
]
}
]
}
Gut eingewickelt in den OpenAPI-Wrapper
Zur Interaktion mit ChatGPT dient die OpenAI-API. Voraussetzung dafür ist ein API-Schlüsselfür den ein kostenpflichtiger OpenAI-Account erforderlich ist.
Für die Kommunikation mit OpenAI kommt der Http-Client Axios zum Einsatz, der sich mit
npm install axios
installieren lässt.
Der folgende Code zeigt ein Wrapper-Skript mit dem Namen „your-chatgpt-wrapper“. Das Skript muss den zuvor generierten API-Key und die dazugehörige API-URL enthalten. Es empfiehlt sich, mindestens den Wert für den API-Key aus einem sicheren Secret Store zu laden, statt ihn im Skript fest zu kodieren.
import axios from 'axios';
const API_KEY = 'your_openai_api_key';
const API_URL =
'https://api.openai.com/v1/chat/completions';
// Configure Axios instance
const axiosInstance = axios.create({
baseURL: API_URL,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`,
},
});
export async function chatGpt(prompt: string):
Promise {
try {
const response = await axiosInstance.post('', {
messages: [
{ role: "user", content: prompt}
],
max_tokens: 100,
n: 1,
stop: null,
temperature: 0.7,
});
const generatedCode =
response.data.choices[0].message.content.trim();
return generatedCode || '';
} catch (error) {
console.error('Error while communicating with ' +
'ChatGPT API:', error);
throw error;
}
}
export async function generateJasmineTest(testCase: any):
Promise {
const prompt = `Generate a Jasmine unit test
for the following test case:
\n\n${JSON.stringify(testCase, null, 2)}\n\n
Jasmine test:`;
return chatGpt(prompt);
}
export async function
generateCypressTest(testCase: any): Promise {
const prompt = `Generate a Cypress E2E test for
the following test case:
\n\n${JSON.stringify(testCase, null, 2)}\n\n
Cypress test:`;
return chatGpt(prompt);
}
Der Code schickt die API-Anfragen mit Axios an den ChatGPT-API-Endpunkt. Daneben enthält er zwei weitere Funktionen: generateJasmineTest
und generateCypressTest
. Sie verwenden jeweils einen Testfall als Eingabe und geben den Testcode als Ausgabe zurück.
Eventuell sind einige Anpassungen erforderlich, um die ChatGPT-Antworten optimal zu nutzen, einschließlich der Auswahl unterschiedlicher Parameter für die API-Anfrage wie max_tokens
, temperature
oder stop
. Die beste Vorgehensweise hängt von den spezifischen Anforderungen und dem gewünschten Testcode ab.