Testing av kunstig intelligens
Testing av kunstig intelligens
Kunstig intelligens gjør utvikling mange ganger raskere enn før. Den kan lage kode som kompilerer og ser fint ut, men hvordan vet vi om det fungerer? Vi må teste.
Når KI genererer kode kan testing bli en flaskehals. Det blir fort uoverkommelig å teste selv et enkelt program manuelt hver gang Claude gjør en endring. Derfor trenger vi automatisk testing.
Men hvordan spesifiserer vi disse testene?
Spørsmålet er egentlig feil. Det er for sent å spesififisere når man tester. Spesifikasjonen bør komme først, så implementasjon, så test. Heldigvis finnes det gode, smidige metoder for dette som passer godt sammen med KI.
flowchart LR
Spesifikasjon --> Kode --> Test
Spesifikasjon --> Test
Spesifikasjon med eksempler
Behaviour Driven Development (BDD) er en måte å beskrive oppførsen til systemet med eksempler, f.eks:
Given a user alf@test.com with password secret123
When the user enters username alf@test.com and password secret123
Then the user should be redirected to their dashboard
Dette formatet er både lettlest og strukturert. Det er lett å forstå for utviklere, testere og brukere, og det strukturert nok til at det kan tolkes av en datamaskin og kjøres automatisk.
For å kjøret testene må man skrive “lim” som oversetter tekst til kjørbar kode, f.eks:
public class StepDefinitions {
@Given("a user {username} with password {password}")
public void prepare_user(String username, String password) {
// TODO
}
@When("the user enters username {username} and password {password}")
public void login(String username, String password) {
// TODO
}
@Then("the user should be redirected to their dashboard")
public void verify_start_page() {
// TODO
}
}
Å vedlikeholde denne koden blir mye jobb etter hvert, men boilerplate kode som dette er KI god på å lage.
Eksempler på eksempler
Jeg har laget en app for å lære italiensk med hjelp av KI. Claude Code gjorde meg veldig produktiv men ødela stadig logikk som fungerte tidligere. F.eks. vil jeg at ord skal gjentas til brukeren har svart riktig 3 dager på rad, og igjen om 1 uke og 1 mnd. Når Claude laget ny funksjonalitet i appen gikk denne logikken ofte i stykker.
For å forhindre dette laget jeg (og Claude) laget et antall eksempler slik som dette:
### Learning words
Given 10 words: word1, word2, word3, word4, word5, word6, word7, word8, word9, word10
And these attempts:
- word1: wrong+correct, wrong+correct, correct
- word2: wrong+correct, wrong+correct, correct
- word3: wrong+correct, correct, correct
- word4: wrong+correct, correct, correct
- word5: correct
When a new round starts on day 5
Then the app shows these words in random order: word1, word2, word6, word7, word8
And word3 and word4 will not be shown because they were mastered less than 7 days ago
Så ba jeg Claude til å bruke dette som input til unit tester. Eksemplene brukes ikke til å generere kode, men som input til unit testene. Claude laget en parser som mater eksempel-verdiene inn i koden og tester den.
Slik ser det ut når testene er kjørt i IntelliJ:

Et tips: Verifiser at testene feiler når de skal.
Her er min instruksjon til Claude:
Specification
The functional behavior is described in a specification, usually in spec.md
The behaviour is described with:
- objects which describes the business objects and values
- examples that consist of objects, input and output.
Each example is described with BDD:
Given <initial objects>
When <input>
And <input>
Then <result objects or output>
And <result objects or output>
Note that objects, input or output may span multiple lines.
Initial objects and result objects refers to domain objects for the application. Initial objects can be configuration or pre-existing data. Result objects refers to domain objects for the application that should be modified.
Input is external input what triggers the behavior. It may be user input or specific times. This should be mapped to business logic in the application.
Output may be output to the user.
Make sure that all result objects and output can be calculated from the initial objects and input. Either the same values are used or the logic is specified.
If it is not clear how the objects, input or output are mapped to the code, ask.
Unit testing
- Prepare data objects for the initial state.
- Trigger the behavior by calling the business logic.
- Verify the result objects and output.
When unit testing:
- Use values from the examples as initial objects and input parameters.
- Verify that the result objects and output have values from the examples.
- Avoid mocking. Generate code that is testable without mocking. If you need to mock, ask if the code can be refactored to avoid it.
Make a test driver that reads spec file, finds examples and tests them. Make logic to parse values from test steps (given, when + and, then + and) and translate that to objects and function calls at runtime. Unit tests should fail on missing step definitions or value mappings.