Lär dig en Claude Code-prompt för testgenerering som ger högsignaltester genom att rikta in sig på gränser, invarianter och felmoder istället för bara happy paths.

Automatiskt genererade testsuiter ser ofta imponerande ut: dussintals tester, mycket setup-kod, och varje funktionsnamn dyker upp någonstans. Men många av dessa tester är bara kontroller av "det fungerar när allt är normalt". De går igenom lätt, fångar sällan buggar och kostar fortfarande tid att läsa och underhålla.
Med en typisk Claude Code-prompt för testgenerering tenderar modellen att spegla de exempelindata den ser. Du får variationer som ser annorlunda ut men täcker samma beteende. Resultatet blir en stor suite med tunn täckning där det verkligen spelar roll.
Högsignaltester är annorlunda. Det är den lilla uppsättning som skulle ha fångat förra månadens incident. De misslyckas när beteendet ändras på ett riskabelt sätt, och förblir stabila vid harmlösa refaktorer. Ett högsignaltest kan vara värt tjugo "returnerar förväntat värde"-kontroller.
Låg-värdes happy-path-generering har ofta några tydliga symtom:
Föreställ dig en funktion som applicerar en rabattkod. Happy-path-tester bekräftar att "SAVE10" sänker priset. Riktiga buggar gömmer sig någon annanstans: 0 eller negativa priser, utgångna koder, avrundningskanter eller maximala rabattgränser. Det är de fallen som orsakar felaktiga totalsummor, arga kunder och midnattsåterställningar.
Målet är att gå från "fler tester" till "bättre tester" genom att sikta på tre mål: gränser, felmoder och invarianter.
Om du vill ha högsignal-enhetstester, sluta be om "fler tester" och börja be om tre specifika typer. Detta är kärnan i en Claude Code-prompt som ger användbar täckning istället för en hög med "fungerar för normal input"-kontroller.
Gränser är kanterna av vad koden accepterar eller producerar. Många verkliga defekter är off-by-one, tomt-läge eller timeout-problem som aldrig syns i en happy path.
Tänk i termer av minimum och maximum (0, 1, maxlängd), tomt vs närvarande ("", [], nil), off-by-one (n-1, n, n+1) och tidsgränser (nära cutoff).
Exempel: om ett API accepterar "upp till 100 artiklar", testa 100 och 101, inte bara 3.
Felmoder är sätt som systemet kan gå sönder på: felaktiga indatavärden, saknade beroenden, partiella resultat eller upstream-fel. Bra felmodtester kontrollerar beteende under stress, inte bara output i idealiska förhållanden.
Exempel: när ett databasanrop misslyckas, returnerar funktionen då ett tydligt fel och undviker att skriva partiella data?
Invarianter är sanningar som ska förbli sanna före och efter ett anrop. De förvandlar vag korrekthet till klara assertioner.
Exempel:
När du fokuserar på dessa tre mål får du färre tester, men varje test bär mer signal.
Om du ber om tester för tidigt får du oftast en hög av artiga "fungerar som förväntat"-kontroller. En enkel lösning är att först skriva ett litet kontrakt och sedan generera tester från det. Det är det snabbaste sättet att göra en Claude Code-prompt till något som hittar verkliga buggar.
Ett användbart kontrakt är kort nog att läsa i ett andetag. Sikta på 5 till 10 rader som svarar på tre frågor: vad går in, vad kommer ut, och vad ändras annars.
Skriv kontraktet i enkelt språk, inte i kod, och inkludera bara det som går att testa.
När du har det, skanna efter var verkligheten kan bryta dina antaganden. De blir gränsfall (min/max, noll, overflow, tomma strängar, dubbletter) och felmoder (timeouts, permission denied, unique constraint-violations, korrupt input).
Här är ett konkret exempel för en funktion som reserveInventory(itemId, qty):
Kontraktet kan säga att qty måste vara ett positivt heltal, funktionen ska vara atomisk och den får aldrig skapa negativ lager. Det föreslår snabbt högsignaltester: qty = 0, qty = 1, qty större än tillgängligt, samtidiga anrop och ett tvingat databasfel mitt i.
Om du använder ett verktyg som Koder.ai gäller samma arbetsflöde: skriv kontraktet i chatten först, generera sedan tester som direkt attackerar gränser, felmoder och "får aldrig hända"-listan.
Använd denna Claude Code-prompt när du vill ha färre tester men där varje test gör nytta. Nyckelsteg är att tvinga fram en testplan först och sedan generera testkod bara efter att du godkänt planen.
You are helping me write HIGH-SIGNAL unit tests.
Context
- Language/framework: <fill in>
- Function/module under test: <name + short description>
- Inputs: <types, ranges, constraints>
- Outputs: <types + meaning>
- Side effects/external calls: <db, network, clock, randomness>
Contract (keep it small)
1) Preconditions: <what must be true>
2) Postconditions: <what must be true after>
3) Error behavior: <how failures are surfaced>
Task
PHASE 1 (plan only, no code):
A) Propose 6-10 tests max. Do not include “happy path” unless it protects an invariant.
B) For each test, state: intent, setup, input, expected result, and WHY it is high-signal.
C) Invariants: list 3-5 invariants and how each will be asserted.
D) Boundary matrix: propose a small matrix of boundary values (min/max/empty/null/off-by-one/too-long/invalid enum).
E) Failure modes: list negative tests that prove safe behavior (no crash, no partial write, clear error).
Stop after PHASE 1 and ask for approval.
PHASE 2 (after approval):
Generate the actual test code with clear names and minimal mocks.
En praktisk trick är att kräva gränsmatrisen som en kompakt tabell så att luckor blir uppenbara:
| Dimension | Giltig kant | Precis utanför | "Konstig" värde | Förväntat beteende |
|---|---|---|---|---|
| length | 0 | -1 | 10,000 | error vs clamp vs accept |
Om Claude föreslår 20 tester, pressa tillbaka. Be den slå ihop liknande fall och behålla bara de som skulle fånga en verklig bugg (off-by-one, fel feltyp, tyst databortfall, brutet invariant).
Börja med ett litet, konkret kontrakt för det beteende du vill ha. Klistra in funktionssignaturen, en kort beskrivning av inputs och outputs, och eventuella befintliga tester (även om de bara är happy-path). Det håller modellen förankrad i vad koden faktiskt gör, inte i vad den gissar.
Be sedan om en risk-tabell innan du ber om någon testkod. Kräv tre kolumner: gränsfall (kanter av giltig input), felmoder (dålig input, saknad data, timeouts) och invarianter (saker som alltid måste gälla). Lägg till en mening per rad: "varför detta kan gå sönder." En enkel tabell visar luckor snabbare än en hög med testfiler.
Välj sedan den minsta uppsättningen tester där varje test har ett unikt buggfångande syfte. Om två tester misslyckas av samma anledning, behåll det starkare.
En praktisk selektionsregel:
Slutligen, kräva en kort förklaring per test: vilken bugg den skulle fånga om den misslyckas. Om förklaringen är vag ("validerar beteende") är testet troligen låg-signal.
En invariant är en regel som ska förbli sann oavsett vilken giltig input du skickar in. Med invariantbaserad testning skriver du först regeln i klartext och omvandlar den sedan till en assertion som kan misslyckas högljutt.
Välj 1–2 invarianter som faktiskt skyddar dig från verkliga buggar. Bra invarianter handlar ofta om säkerhet (ingen databortfall), konsekvens (samma input → samma output) eller gränser (överskrid aldrig caps).
Skriv invariant som en kort mening, bestäm sedan vilket bevis ditt test kan observera: returvärden, sparade data, emitterade events eller anrop till beroenden. Starka assertioner kontrollerar både utfall och sidoeffekter, eftersom många buggar gömmer sig i "det returnerade OK, men skrev fel."
Till exempel, säg att du har en funktion som applicerar en kupong på en order:
Nu koda dem som konkreta assertioner:
expect(result.total).toBeGreaterThanOrEqual(0)
expect(db.getOrder(orderId).discountCents).toBe(originalDiscountCents)
Undvik vagt formulerade asserts som "returnerar förväntat resultat". Asserta den specifika regeln (icke-negativ) och den specifika sidoeffekten (rabatt lagrad en gång).
För varje invariant, lägg till en kort notering i testet om vilken data som skulle bryta mot den. Det hindrar testet från att glida in i ett happy-path-check senare.
Ett enkelt mönster som håller över tid:
Högsignaltester är ofta de som bekräftar att din kod misslyckas säkert. Om en modell bara skriver happy-path-tester lär du dig nästan ingenting om hur funktionen beter sig när indatan och beroenden blir röriga.
Börja med att bestämma vad "säkert" betyder för den här funktionen. Returnerar den ett typat fel? Fall back till ett default? Försöker den en gång till och ger upp? Skriv det förväntade beteendet i en mening och låt testerna bevisa det.
När du ber Claude Code om felmodtester, håll målet strikt: täck de sätt systemet kan gå sönder och asserta exakt det svar du vill ha. En användbar formulering är: "Föredra färre tester med starkare assertioner framför många grunda tester."
Fel-kategorier som ofta ger bäst tester:
Exempel: du har ett endpoint som skapar en användare och kallar en e-posttjänst för att skicka ett välkomstmeddelande. Ett låg-värde-test kontrollerar "returnerar 201." Ett högsignal-feltest kontrollerar att om e-posttjänsten timear ut, så antingen (a) skapas användaren ändå och 201 returneras med en "email_pending"-flagga, eller (b) returnera en tydlig 503 och skapa inte användaren. Välj ett beteende och asserta både respons och sidoeffekter.
Testa också vad du inte läcker. Om validering misslyckas, se till att ingenting skrivs till databasen. Om ett beroende returnerar korrupt payload, se till att du inte kastar en ohandterad exception eller returnerar råa stacktraces.
Låg-värdes testuppsättningar uppstår ofta när modellen belönas för volym. Om din Claude Code-prompt ber om "20 enhetstester" får du ofta små variationer som ser grundliga ut men fångar ingenting nytt.
Vanliga fallgropar:
Exempel: föreställ dig en "create user"-funktion. Tio happy-path-tester kan variera email-strängen och ändå missa viktiga saker: avvisa dubbletter, hantera tomt lösenord och garantera att returnerade användar-ID:n är unika och stabila.
Styrregler som hjälper i granskning:
Föreställ dig en funktion: applicera en kupongkod i kassan.
Kontrakt (litet och testbart): givet en kundvagnssubtotal i cent och en valfri kupong, returnera en slutlig total i cent. Regler: procentkuponger avrundas nedåt till närmaste cent, fasta kuponger drar av ett fast belopp, och totalsummor blir aldrig negativa. En kupong kan vara ogiltig, utgången eller redan använd.
Begär inte "tester för applyCoupon()". Be om gränsfallstestning, felmodtester och invarianter knutna till detta kontrakt.
Välj indatavärden som tenderar att bryta matte eller validering: en tom kupongsträng, subtotal = 0, subtotal precis under och över ett minsta köp, en fast rabatt större än subtotalen, och en procent som 33% som skapar avrundning.
Anta att kupongsökning kan misslyckas och tillståndet kan vara fel: kupongtjänsten är nere, kupongen är utgången eller redan inlöst av denna användare. Testet ska bevisa vad som händer härnäst (kupongen avvisas med ett tydligt fel, totalen oförändrad).
En minimal, högsignal testuppsättning (5 tester) och vad varje test fångar:
Om dessa passerar har du täckt vanliga brytpunkter utan att fylla suiten med dubbletta happy-path-tester.
Innan du accepterar vad modellen genererar, gör en snabb kvalitetsgenomgång. Målet är tester som var och en skyddar dig från en specifik, sannolik bugg.
Använd denna checklista som grind:
Ett snabbt praktiskt trick efter generering: döp om tester till "should <beteende> when <kantvillkor>" och "should not <dåligt utfall> when <fel>". Om du inte kan döpa dem snyggt är de inte fokuserade.
Om du bygger med Koder.ai, passar denna checklista också bra med snapshots och rollback: generera tester, kör dem, och rollback om den nya uppsättningen lägger till brus utan att förbättra täckningen.
Behandla din prompt som ett återanvändbart redskap, inte en engångsförfrågan. Spara en blåkopia av prompten (den som tvingar fram gränser, felmoder och invarianter) och återanvänd den för varje ny funktion, endpoint eller UI-flöde.
En enkel vana som snabbt förbättrar resultat: be om en mening per test som förklarar vilken bugg den skulle fånga. Om den meningen är generisk är testet troligen brus.
Behåll en levande lista över domäninvarianter för din produkt. Förvara den inte i huvudet. Lägg till när du hittar en verklig bugg.
Ett lättviktigt arbetsflöde du kan upprepa:
Om du bygger appar via chat, kör denna cykel inne i Koder.ai (koder.ai) så kontraktet, planen och genererade tester ligger på ett ställe. När en refaktor ändrar beteende oväntat gör snapshots och rollback det enklare att jämföra och iterera tills din högsignaluppsättning förblir stabil.
Standard: sikta på en liten uppsättning som skulle fånga en verklig bugg.
Ett enkelt tak som fungerar väl är 6–10 tester per enhet (funktion/modul). Om du behöver fler betyder det oftast att din enhet gör för mycket eller att kontraktet är oklart.
Happy-path-tester bevisar mestadels att ditt exempel fortfarande fungerar. De missar ofta det som går sönder i produktion.
Högsignaltester riktar sig mot:
Börja med ett litet kontrakt som du kan läsa i en mening:
Generera sedan tester från det kontraktet, inte bara från exempel.
Testa dessa först:
Välj en eller två per indata-dimension så varje test täcker en unik risk.
Ett bra felmodstest bevisar två saker:
Om en databasinskrivning är inblandad, kontrollera vad som hände i lagringen efter felet.
Standardmetod: gör invarianter till assertioner på observerbara utfall.
Exempel:
expect(total).toBeGreaterThanOrEqual(0)Det är värt att behålla ett happy-path-test när det skyddar en invariant eller en kritisk integration.
Bra skäl att behålla ett:
Annars byt det mot gräns-/feltester som fångar fler buggklasser.
Tvinga fram PHASE 1: endast plan först.
Kräv att modellen levererar:
Först efter godkänd plan ska den generera kod. Det förhindrar "20 look-alike"-tester.
Standard: mocka bara den gräns du inte äger (DB/nätverk/klocka) och håll allt annat verkligt.
För att undvika övermockning:
Om ett test går sönder på refaktor men beteendet inte ändrats är det ofta övermockat eller för implementation-kopplat.
Använd ett enkelt "slet-test":
Sök också efter dubbletter:
Föredra att kontrollera både returvärde och sidoeffekter, eftersom många buggar döljer sig i "returer OK men skrev fel".