# AI Destekli Unit Test Üretimi: Claude Code + Cursor ile 2026 Workflow
2025'te AI ile kod yazıyordunuz. 2026'da AI ile test yazıyorsunuz. Bu farkı küçümsemeyin — test yazma, çoğu zaman kod yazmaktan daha zor. Edge case'leri bulmak, mock stratejisi kurmak, assertion'ları doğru yazmak deneyim gerektiriyor. AI bu deneyimi herkes için erişilebilir kılıyor.
50.000 satır TypeScript koduna sahip bir projede AI yardımıyla test coverage'ı %78'den %94'e çıkardım. Bu süreçte öğrendiklerimi paylaşıyorum.
Pro Tip: AI'a test ürettirmeden önce "Bu fonksiyonun hangi edge case'leri olabilir?" diye sorun, doğrudan test yazdırmayın. Edge case listesi aldıktan sonra test üretimi çok daha hedefli oluyor ve gözden kaçan senaryolar azalıyor.
İçindekiler
- Neden AI Destekli Test?
- Claude Code ile Test Generation
- Cursor Test Agent Workflow
- Edge Case Mining Teknikleri
- Mocking Stratejileri
- Coverage Analizi ve Optimizasyon
- Property-Based Testing ile AI
- Snapshot Test Review
- Flaky Test Tespiti
- Team Workflow ve Standartlar
1. Neden AI Destekli Test?
Yazılım geliştiricilerin test yazmamasının iki ana nedeni var: zaman ve zihinsel efor. Bir fonksiyonu yazdıktan sonra test yazmak, aynı problemi ikinci kez çözmek gibi hissettiriyor. AI bu algıyı değiştiriyor.
Gerçek metrikler (50K LOC projede):
Metrik | AI Öncesi | AI Sonrası |
|---|---|---|
Test yazma hızı | ~15 test/gün | ~60 test/gün (4x) |
Test coverage | %78 | %94 |
Edge case tespiti | Manual | AI assisted |
Ortalama test kalitesi | Orta | Yüksek |
Flaky test oranı | %12 | %3 |
Bu rakamlar tek kişilik effort. Takım genelinde ölçüldüğünde etkisi daha da büyük — junior geliştiriciler deneyimli developerların seviyesinde test yazabiliyor.
AI'nın güçlü olduğu alanlar:
- Boundary value analysis (sınır değer analizi)
- Negative test cases (hata yolları)
- Null/undefined handling
- Type edge cases (0, empty string, very large numbers)
- Async error scenarios
- Race conditions (önerebilir, garantileyemez)
AI'nın zayıf olduğu alanlar:
- Domain-specific business logic edge cases (müşteri sipariş kuralları, vergi hesaplama mantığı)
- Integration test setup (gerçek database, external service)
- Visual regression test
- Performance benchmark test
2. Claude Code ile Test Generation
Claude Code'un /test komutu, açık dosyayı analiz edip test üretir. Ama raw output yerine prompt engineering ile çok daha kaliteli sonuç alınıyor.
Temel kullanım:
bash
1# Claude Code terminal'de2claude3 4# Dosyayı açıkla ve test iste5> /test src/lib/pricing.tsDaha etkili prompt pattern'leri:
swift
1# Pattern 1: Edge case mining önce2"Bu fonksiyonun edge case'lerini listele, henüz test yazma:3[fonksiyon kodu]"4 5# Pattern 2: Belirli framework ile6"Vitest kullanarak, AAA pattern ile (Arrange/Act/Assert)7şu fonksiyon için test yaz. Her test independent olsun:8[fonksiyon kodu]"9 10# Pattern 3: Coverage odaklı11"Şu test suite'e bakarak, hangi dallar test edilmemiş?12Eksik coverage için testler üret:13[mevcut testler]14[kaynak kod]"15 16# Pattern 4: Regression test17"Bu bug fix için regression test yaz.18Bug: [açıklama]19Fix: [kod değişikliği]"Gerçek örnek — pricing.ts:
typescript
1// src/lib/pricing.ts2interface PricingInput {3 basePrice: number;4 quantity: number;5 discountCode?: string;6 userType: "guest" | "member" | "premium";7}8 9interface PricingResult {10 subtotal: number;11 discount: number;12 tax: number;13 total: number;14}15 16const DISCOUNT_CODES: Record = { 17 SAVE10: 0.1,18 SAVE20: 0.2,19 WELCOME: 0.15,20};21 22const USER_TYPE_DISCOUNTS = {23 guest: 0,24 member: 0.05,25 premium: 0.1,26};27 28const TAX_RATE = 0.18;29 30export function calculatePrice(input: PricingInput): PricingResult {31 if (input.basePrice < 0) {32 throw new Error("Base price cannot be negative");33 }34 if (input.quantity <= 0) {35 throw new Error("Quantity must be positive");36 }37 38 const subtotal = input.basePrice * input.quantity;39 40 let discountRate = USER_TYPE_DISCOUNTS[input.userType];41 42 if (input.discountCode) {43 const codeDiscount = DISCOUNT_CODES[input.discountCode] ?? 0;44 // Discounts stack (additive, not multiplicative)45 discountRate = Math.min(discountRate + codeDiscount, 0.5);46 }47 48 const discount = subtotal * discountRate;49 const afterDiscount = subtotal - discount;50 const tax = afterDiscount * TAX_RATE;51 const total = afterDiscount + tax;52 53 return {54 subtotal: Math.round(subtotal * 100) / 100,55 discount: Math.round(discount * 100) / 100,56 tax: Math.round(tax * 100) / 100,57 total: Math.round(total * 100) / 100,58 };59}Claude Code'a verince ürettiği testler:
typescript
1// src/lib/pricing.test.ts2import { describe, it, expect } from "vitest";3import { calculatePrice } from "./pricing";4 5describe("calculatePrice", () => {6 describe("temel hesaplama", () => {7 it("misafir kullanıcı için doğru hesaplama yapmalı", () => {8 const result = calculatePrice({9 basePrice: 100,10 quantity: 2,11 userType: "guest",12 });13 14 expect(result.subtotal).toBe(200);15 expect(result.discount).toBe(0);16 expect(result.tax).toBe(36);17 expect(result.total).toBe(236);18 });19 20 it("üye kullanıcı için %5 indirim uygulamalı", () => {21 const result = calculatePrice({22 basePrice: 100,23 quantity: 1,24 userType: "member",25 });26 27 expect(result.discount).toBe(5);28 expect(result.total).toBe(111.65);29 });30 31 it("premium kullanıcı için %10 indirim uygulamalı", () => {32 const result = calculatePrice({33 basePrice: 100,34 quantity: 1,35 userType: "premium",36 });37 38 expect(result.discount).toBe(10);39 expect(result.total).toBe(106.2);40 });41 });42 43 describe("indirim kodu", () => {44 it("geçerli indirim kodu uygulamalı", () => {45 const result = calculatePrice({46 basePrice: 100,47 quantity: 1,48 discountCode: "SAVE20",49 userType: "guest",50 });51 52 expect(result.discount).toBe(20);53 });54 55 it("kullanıcı tipi ve indirim kodu toplamalı (additive)", () => {56 const result = calculatePrice({57 basePrice: 100,58 quantity: 1,59 discountCode: "SAVE10",60 userType: "member",61 });62 63 // member %5 + SAVE10 %10 = %15 toplam64 expect(result.discount).toBe(15);65 });66 67 it("toplam indirim %50yi geçmemeli (cap)", () => {68 const result = calculatePrice({69 basePrice: 100,70 quantity: 1,71 discountCode: "SAVE20",72 userType: "premium",73 });74 75 // premium %10 + SAVE20 %20 = %30, cap yok bu vakada76 expect(result.discount).toBe(30);77 });78 79 it("premium + SAVE20 => %30, save20 + büyük indirim cap'i test et", () => {80 // %10 + %20 + %20 gibi bir senaryo için cap test81 // SAVE20 kodu ile premium: 0.10 + 0.20 = 0.30 < 0.50, cap'e takılmaz82 const result = calculatePrice({83 basePrice: 1000,84 quantity: 1,85 discountCode: "SAVE20",86 userType: "premium",87 });88 89 expect(result.discount).toBe(300);90 expect(result.discount / result.subtotal).toBeLessThanOrEqual(0.5);91 });92 93 it("geçersiz indirim kodu 0 indirim uygulamalı", () => {94 const result = calculatePrice({95 basePrice: 100,96 quantity: 1,97 discountCode: "INVALID_CODE",98 userType: "guest",99 });100 101 expect(result.discount).toBe(0);102 });103 });104 105 describe("hata durumları", () => {106 it("negatif fiyat için hata fırlatmalı", () => {107 expect(() =>108 calculatePrice({109 basePrice: -10,110 quantity: 1,111 userType: "guest",112 })113 ).toThrow("Base price cannot be negative");114 });115 116 it("sıfır miktar için hata fırlatmalı", () => {117 expect(() =>118 calculatePrice({119 basePrice: 100,120 quantity: 0,121 userType: "guest",122 })123 ).toThrow("Quantity must be positive");124 });125 126 it("negatif miktar için hata fırlatmalı", () => {127 expect(() =>128 calculatePrice({129 basePrice: 100,130 quantity: -1,131 userType: "guest",132 })133 ).toThrow("Quantity must be positive");134 });135 });136 137 describe("edge cases", () => {138 it("sıfır fiyat geçerli olmalı", () => {139 const result = calculatePrice({140 basePrice: 0,141 quantity: 1,142 userType: "guest",143 });144 145 expect(result.total).toBe(0);146 });147 148 it("çok büyük sayılar için doğru yuvarlama yapmalı", () => {149 const result = calculatePrice({150 basePrice: 99.99,151 quantity: 3,152 userType: "guest",153 });154 155 expect(result.subtotal).toBe(299.97);156 expect(result.total).toBe(353.96);157 });158 159 it("1 miktarında doğru hesaplama yapmalı", () => {160 const result = calculatePrice({161 basePrice: 100,162 quantity: 1,163 userType: "guest",164 });165 166 expect(result.subtotal).toBe(100);167 });168 });169});3. Cursor Test Agent Workflow
Cursor'un Composer (Ctrl+I) özelliği, test dosyası olmayan bir source file seçince otomatik test üretiyor. Ama asıl güç, Chat modunda iteratif çalışmak.
Cursor workflow:
- Source file'ı açın
- Sağ panel Chat'te şunu yazın: "Bu dosya için kapsamlı Vitest testleri yaz, coverage'ı maximize et"
- Üretilen testi
cmd+Kile dosyaya uygulayın vitest run --coverageçalıştırın- Eksik coverage görünce Chat'e geri dönün: "şu satırlar hala covered değil: [satır numaraları], eksik testleri ekle"
Cursor'a özel prompt teknikleri:
swift
1# Bağlamı genişlet: birden fazla dosya seç2"@pricing.ts ve @discount-rules.ts birlikte göz önünde bulundurarak3integration testleri yaz"4 5# Test fix isteme6"@pricing.test.ts — 3. test failing, error: [hata mesajı]7Testi düzelt ama mantığı değiştirme"8 9# Refactor sonrası test güncelleme10"pricing.ts refactor edildi. Testleri yeni implementasyona uyarla,11test logic'i koru"4. Edge Case Mining Teknikleri
AI'nın en değerli katkısı edge case bulmak. Manuel olarak gözden kaçırdığınız senaryoları AI sistematik şekilde buluyor.
Standart edge case kategorileri:
typescript
1// AI'a verilen prompt kategorileri2 3// 1. Boundary Values (Sınır Değerler)4// - MIN değer (0, -1, MIN_SAFE_INTEGER)5// - MAX değer (Number.MAX_SAFE_INTEGER, MAX_ARRAY_LENGTH)6// - Tam sınır (0 vs -1, length vs length-1)7 8// 2. Null/Undefined9// - null input10// - undefined input11// - optional field missing vs null12// - empty object {}13// - empty array []14 15// 3. String Edge Cases16// - empty string ""17// - whitespace only " "18// - very long string (1000+ chars)19// - special characters <>&"'20// - unicode characters (emoji, RTL text)21// - SQL injection patterns22// - XSS patterns (not for security test, for type safety)23 24// 4. Number Edge Cases25// - 0 ve -0 (evet, JavaScript'te farklı!)26// - NaN27// - Infinity ve -Infinity28// - Float precision (0.1 + 0.2)29// - Very small decimal (0.001)30 31// 5. Async Edge Cases32// - Promise resolve33// - Promise reject34// - Timeout/AbortSignal35// - Multiple concurrent calls36// - Race condition simulationGerçek edge case örnekleri:
typescript
1// AI'ın bulduğu edge case (ben kaçırmıştım)2it("0 ve -0 aynı davranmalı", () => {3 // JavaScript'te 0 === -0 true döner4 // Ama Object.is(0, -0) false döner5 // calculatePrice'a -0 geçilirse ne olur?6 const result = calculatePrice({7 basePrice: -0, // Negatif sıfır!8 quantity: 1,9 userType: "guest",10 });11 // -0 < 0 false döner, bu yüzden hata fırlatmaz12 // Ama subtotal -0 * 1 = -0 olur... sorunlu!13 expect(result.total).toBe(0);14});15 16it("float precision sorunu olmamalı", () => {17 // 0.1 + 0.2 = 0.30000000000000004 sorunu18 const result = calculatePrice({19 basePrice: 0.1,20 quantity: 3,21 userType: "guest",22 });23 // Math.round ile çözülmüş, ama test ile doğrulayalım24 expect(result.subtotal).toBe(0.3);25 expect(result.subtotal).not.toBe(0.30000000000000004);26});5. Mocking Stratejileri
AI en çok mocking konusunda değer katıyor. Dependency injection pattern olmayan legacy kodu test etmek için AI akıllı mock stratejileri üretiyor.
typescript
1// Dependency Injection ile testable kod2// Önce: direkt import, test edilemez3import { sendEmail } from "../services/email";4 5export async function processOrder(order: Order) {6 // ... işlem7 await sendEmail(order.userEmail, "Order confirmed");8}9 10// Sonra: DI pattern, test edilebilir11export async function processOrder(12 order: Order,13 emailService: { send: (to: string, subject: string) => Promise } = defaultEmailService 14) {15 // ... işlem16 await emailService.send(order.userEmail, "Order confirmed");17}typescript
1// AI üretimli mock örneği2import { describe, it, expect, vi, beforeEach } from "vitest";3import { processOrder } from "./order-processor";4 5describe("processOrder", () => {6 const mockEmailService = {7 send: vi.fn().mockResolvedValue(undefined),8 };9 10 beforeEach(() => {11 vi.clearAllMocks();12 });13 14 it("başarılı sipariş sonrası email gönderilmeli", async () => {15 const order = {16 userEmail: "[email protected]",17 items: [{ productId: "prod-1", quantity: 2 }],18 };19 20 await processOrder(order, mockEmailService);21 22 expect(mockEmailService.send).toHaveBeenCalledOnce();23 expect(mockEmailService.send).toHaveBeenCalledWith(24 "[email protected]",25 "Order confirmed"26 );27 });28 29 it("email gönderimi başarısız olsa bile sipariş işlenmeli", async () => {30 mockEmailService.send.mockRejectedValueOnce(new Error("SMTP error"));31 32 const order = {33 userEmail: "[email protected]",34 items: [{ productId: "prod-1", quantity: 1 }],35 };36 37 // Email hatası siparişi patlatmamalı38 await expect(processOrder(order, mockEmailService)).resolves.not.toThrow();39 });40 41 it("email servisi hiç çağrılmasa ne olur? (empty items)", async () => {42 const order = {43 userEmail: "[email protected]",44 items: [],45 };46 47 // Boş sipariş — email gönderilmemeli mi? Business logic'e göre değişir48 // AI bu soruyu da işaret ediyor: "Bu case'de ne olması gerektiğini belirtin"49 await processOrder(order, mockEmailService);50 51 // Beklentiyi business logic'e göre belirle52 expect(mockEmailService.send).not.toHaveBeenCalled();53 });54});Module mock için vi.mock:
typescript
1// External module mock2vi.mock("../services/analytics", () => ({3 track: vi.fn(),4 identify: vi.fn(),5}));6 7// Partial mock (bazı fonksiyonları gerçek tut)8vi.mock("../utils/date", async (importOriginal) => {9 const actual = await importOriginal(); 10 return {11 ...actual,12 now: vi.fn(() => new Date("2026-04-18T12:00:00Z")),13 };14});6. Coverage Analizi ve Optimizasyon
AI coverage raporunu analiz edip hangi testlerin öncelikli olduğunu söyleyebiliyor.
bash
1# Vitest coverage raporu2npx vitest run --coverage --coverage.reporter=json3 4# Raporu AI'a ver ve analiz ettirtypescript
1// vitest.config.ts - coverage konfigürasyonu2import { defineConfig } from "vitest/config";3 4export default defineConfig({5 test: {6 coverage: {7 provider: "v8",8 reporter: ["text", "json", "html"],9 thresholds: {10 lines: 90,11 branches: 85,12 functions: 90,13 statements: 90,14 },15 exclude: [16 "**/*.test.ts",17 "**/*.spec.ts",18 "**/types/**",19 "**/mocks/**",20 "**/__fixtures__/**",21 ],22 },23 },24});Line coverage vs Branch coverage farkı:
typescript
1function getDiscount(userType: string): number {2 if (userType === "premium") { // Branch 1: true/false3 return 0.2;4 }5 return 0; // Branch 1 false: Bu satır çalışıyor6}7 8// Line coverage: Her satır en az bir kez çalıştı mı? %100 olabilir9// Branch coverage: Her if'in hem true hem false dalı test edildi mi?10 11// Sadece şu test varsa:12it("premium indirim", () => {13 expect(getDiscount("premium")).toBe(0.2);14});15 16// Line coverage: %100 (tüm satırlar çalıştı)17// Branch coverage: %50 (sadece true branch test edildi)18// False branch (non-premium) hiç test edilmedi!AI'a coverage raporunu verince şunu söylüyor: "Branch coverage %82, özellikle şu satırlardaki false branch'ler eksik. Şu testleri ekle..."
7. Property-Based Testing ile AI
Property-based testing, belirli input/output örnekleri yerine "bu input tipi için bu property her zaman geçerli olmalı" der. AI bu test türünde özellikle güçlü.
typescript
1// fast-check ile property-based testing2import { describe, it, expect } from "vitest";3import * as fc from "fast-check";4import { calculatePrice } from "./pricing";5 6describe("calculatePrice - property based", () => {7 it("total her zaman pozitif olmalı", () => {8 fc.assert(9 fc.property(10 fc.float({ min: 0, max: 10000, noNaN: true }),11 fc.integer({ min: 1, max: 100 }),12 fc.constantFrom("guest", "member", "premium" as const),13 (basePrice, quantity, userType) => {14 const result = calculatePrice({ basePrice, quantity, userType });15 return result.total >= 0;16 }17 )18 );19 });20 21 it("discount asla subtotal'dan büyük olmamalı", () => {22 fc.assert(23 fc.property(24 fc.float({ min: 0.01, max: 10000, noNaN: true }),25 fc.integer({ min: 1, max: 100 }),26 fc.constantFrom("guest", "member", "premium" as const),27 fc.option(fc.constantFrom("SAVE10", "SAVE20", "WELCOME")),28 (basePrice, quantity, userType, discountCode) => {29 const result = calculatePrice({30 basePrice,31 quantity,32 userType,33 discountCode: discountCode ?? undefined,34 });35 return result.discount <= result.subtotal;36 }37 )38 );39 });40 41 it("subtotal her zaman basePrice * quantity olmalı", () => {42 fc.assert(43 fc.property(44 fc.float({ min: 0, max: 1000, noNaN: true }),45 fc.integer({ min: 1, max: 50 }),46 (basePrice, quantity) => {47 const result = calculatePrice({48 basePrice,49 quantity,50 userType: "guest",51 });52 const expected = Math.round(basePrice * quantity * 100) / 100;53 return Math.abs(result.subtotal - expected) < 0.01;54 }55 )56 );57 });58});AI'a "Bu fonksiyon için hangi property'ler her zaman geçerli olmalı?" diye sorduğumda verdiği cevap:
- total = subtotal - discount + tax (matematiksel tutarlılık)
- 0 <= discountRate <= 0.5 (cap garantisi)
- tax = (subtotal - discount) * TAX_RATE (vergi hesabı)
- total >= 0 her zaman
- Aynı input => aynı output (pure function)
Bu property'lerin her biri bir test grubuna dönüşüyor.
8. Snapshot Test Review
Snapshot testler değişip değişmediğini test eder, doğruluğu değil. AI snapshot'ları review edip "bu snapshot mantıklı mı?" sorusunu cevaplayabiliyor.
typescript
1// Component snapshot test2import { render } from "@testing-library/react";3import { PriceDisplay } from "./PriceDisplay";4 5describe("PriceDisplay snapshot", () => {6 it("fiyat gösterimi değişmemeli", () => {7 const { container } = render(8 9 price={99.99}10 currency="TRY"11 discount={10}12 />13 );14 15 expect(container).toMatchSnapshot();16 });17});AI'a snapshot dosyasını verince şunları söylüyor:
- "Bu snapshot'ta hardcoded class name'ler var, CSS değişince gereksiz fail olur"
- "data-testid kullanın, snapshot'ı semantic HTML'e göre alın"
- "Tarih/zaman içeren snapshot'lar flaky, mock'layın"
AI önerisiyle düzeltilmiş:
typescript
1it("fiyat bilgileri doğru render edilmeli", () => {2 const { getByTestId } = render(3 4 );5 6 // Snapshot yerine semantic assertion7 expect(getByTestId("price-amount")).toHaveTextContent("99,99");8 expect(getByTestId("price-currency")).toHaveTextContent("TRY");9 expect(getByTestId("discount-badge")).toHaveTextContent("%10");10});9. Flaky Test Tespiti
Flaky test: Bazen geçen, bazen geçmeyen test. CI'da güvensizlik yaratır, "tekrar çalıştır" kültürü oluşturur. AI flaky test pattern'lerini tanıyor.
Yaygın flaky test nedenleri:
typescript
1// PROBLEM 1: Date.now() kullanımı2it("created_at bugün olmalı", () => {3 const user = createUser("[email protected]");4 // 23:59'da çalışırsa bugün, 00:01'de çalışırsa dün!5 expect(user.createdAt.toDateString()).toBe(new Date().toDateString());6});7 8// ÇÖZÜM: Date mock9beforeEach(() => {10 vi.useFakeTimers();11 vi.setSystemTime(new Date("2026-04-18T12:00:00Z"));12});13 14afterEach(() => {15 vi.useRealTimers();16});17 18// PROBLEM 2: Order-dependent test19let sharedState = { count: 0 };20 21it("count 0 olmalı", () => {22 expect(sharedState.count).toBe(0); // Test sırası değişince fail!23});24 25it("count increment", () => {26 sharedState.count++;27 expect(sharedState.count).toBe(1);28});29 30// ÇÖZÜM: Her test independent31describe("counter", () => {32 let state: { count: number };33 34 beforeEach(() => {35 state = { count: 0 }; // Her test için sıfırla36 });37 38 it("count 0 olmalı", () => {39 expect(state.count).toBe(0);40 });41});42 43// PROBLEM 3: Async timing44it("debounced search çalışmalı", async () => {45 triggerSearch("query");46 // 300ms debounce var ama setTimeout'u beklemiyoruz47 expect(mockSearchFn).toHaveBeenCalled(); // Flaky!48});49 50// ÇÖZÜM: Fake timers51it("debounced search çalışmalı", async () => {52 vi.useFakeTimers();53 triggerSearch("query");54 await vi.runAllTimersAsync();55 expect(mockSearchFn).toHaveBeenCalled();56 vi.useRealTimers();57});AI'a CI log'larını verince "bu testler neden flaky?" sorusunu analiz ediyor ve yukarıdaki pattern'leri tespit ediyor.
10. Team Workflow ve Standartlar
AI destekli test yazımını takım genelinde standartlaştırmak için:
typescript
1// .cursor/rules veya CLAUDE.md'e eklenecek test standartları2 3/*4TEST STANDARTLARI:51. Her test dosyası: describe > describe > it hiyerarşisi62. Test isimlendirme: "[fonksiyon] - [durum] - [beklenti]" şeklinde73. AAA pattern zorunlu: Arrange, Act, Assert84. Her test bağımsız: beforeEach ile state sıfırla95. Mock'lar dosya üstünde tanımla, test içinde değil106. Assertion mesajları açıklayıcı ol11*/12 13// Takım için test template (snippet olarak kaydet)14describe("[UNIT_NAME]", () => {15 // Arrange - shared setup16 const mockDep = {17 method: vi.fn(),18 };19 20 beforeEach(() => {21 vi.clearAllMocks();22 });23 24 describe("[happy path]", () => {25 it("[beklenen davranış]", () => {26 // Arrange27 const input = {};28 29 // Act30 const result = unitUnderTest(input);31 32 // Assert33 expect(result).toEqual({});34 });35 });36 37 describe("[error cases]", () => {38 it("[hata koşulu] için [beklenen hata]", () => {39 expect(() => unitUnderTest(invalidInput)).toThrow("[error message]");40 });41 });42 43 describe("[edge cases]", () => {44 it("[edge case açıklaması]", () => {45 // ...46 });47 });48});AI test review checklist:
swift
1Test review için Claude'a ver ve şunu sor:2"Bu test suite'i review et:3- Her test gerçekten bir şey test ediyor mu?4- False positive risk var mı? (her zaman geçen ama geçmemesi gereken)5- Coverage'da gözden kaçan alan var mı?6- Mock'lar doğru kullanılmış mı?7- Test isimleri davranışı açıklıyor mu?"ALTIN İPUCU
Bu yazının en değerli bilgisi
Bu ipucu, yazının en önemli çıkarımını içeriyor.
bash
1# Stryker kurulum2npm install --save-dev @stryker-mutator/core @stryker-mutator/vitest-runner3 4# stryker.config.js5export default {6 testRunner: "vitest",7 mutate: ["src/**/*.ts", "!src/**/*.test.ts"],8 reporters: ["html", "json"],9};10 11# Çalıştır12npx stryker runEaster Egg
Gizli bir bilgi buldun!
Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?
swift
1// PricingService.swift2struct PricingService {3 func calculateDiscount(userType: UserType, amount: Double) -> Double {4 switch userType {5 case .guest:6 return 07 case .member:8 return amount * 0.059 case .premium:10 return amount * 0.1011 }12 }13}14 15// AI üretimli XCTest16import XCTest17@testable import MyApp18 19final class PricingServiceTests: XCTestCase {20 var sut: PricingService!21 22 override func setUp() {23 super.setUp()24 sut = PricingService()25 }26 27 override func tearDown() {28 sut = nil29 super.tearDown()30 }31 32 // MARK: - Guest User33 34 func test_calculateDiscount_withGuestUser_returnsZero() {35 let discount = sut.calculateDiscount(userType: .guest, amount: 100)36 XCTAssertEqual(discount, 0, accuracy: 0.001)37 }38 39 // MARK: - Member User40 41 func test_calculateDiscount_withMemberUser_returnsFivePercent() {42 let discount = sut.calculateDiscount(userType: .member, amount: 100)43 XCTAssertEqual(discount, 5.0, accuracy: 0.001)44 }45 46 // MARK: - Premium User47 48 func test_calculateDiscount_withPremiumUser_returnsTenPercent() {49 let discount = sut.calculateDiscount(userType: .premium, amount: 100)50 XCTAssertEqual(discount, 10.0, accuracy: 0.001)51 }52 53 // MARK: - Edge Cases54 55 func test_calculateDiscount_withZeroAmount_returnsZero() {56 let discount = sut.calculateDiscount(userType: .premium, amount: 0)57 XCTAssertEqual(discount, 0, accuracy: 0.001)58 }59 60 func test_calculateDiscount_withLargeAmount_calculatesCorrectly() {61 let discount = sut.calculateDiscount(userType: .member, amount: 99999)62 XCTAssertEqual(discount, 4999.95, accuracy: 0.01)63 }64}Okuyucu Ödülü
Claude Code Swift/XCTest için de test üretiyor:
Sonuç
AI destekli test yazımı 2026'da olgunlaştı. Claude Code ve Cursor kombinasyonu ile test yazma hızı 4x artıyor, coverage %94'e ulaşıyor, flaky test oranı dramatik düşüyor.
En önemli çıkarım: AI testi yazıyor, siz karar veriyorsunuz. Hangi edge case'lerin önemli olduğunu, hangi business logic'in kritik olduğunu siz biliyorsunuz. AI bu kararları destekliyor, yerine geçmiyor.
Test yazmaya başlamak için iyi bir yer: Coverage raporu alın, en düşük coverage'lı 3 dosyayı seçin, AI'a verin ve "bu dosya için kapsamlı testler yaz" deyin. Hafta sonu olmadan coverage'ınız %90 üstüne çıkar.
AI kodlama workflow'unuzu optimize etmek istiyorsanız Claude Computer Use API production rehberine bakabilirsiniz. AI araçlarında yapılan yaygın hataları öğrenmek için AI kod yazmada 10 yanılgı yazısını inceleyebilirsiniz. Zorlu task'larda Claude Opus 4.7'nin ne zaman devreye alınması gerektiğini merak ediyorsanız bu rehber işinize yarayacak.
Faydalı kaynaklar:

