|
| 1 | +--- |
| 2 | +layout: default |
| 3 | +codename: Tessera |
| 4 | +title: Tessera — Habit tracker fejlesztése és tesztelése LLM eszközökkel |
| 5 | +tags: snippets mieset |
| 6 | +authors: Várhegyi Melinda |
| 7 | +--- |
| 8 | + |
| 9 | +# Tessera — Habit tracker fejlesztése és tesztelése LLM eszközökkel |
| 10 | + |
| 11 | +## A feladat leírása |
| 12 | + |
| 13 | +A feladat egy szokáskövető webalkalmazás elkészítése volt, amely alkalmas különböző szokások nyilvántartására és azok teljesítésének követésére. |
| 14 | +A projekt fő témája a **különböző tesztelési módszerek megvalósításának vizsgálata |
| 15 | +LLM-ek segítségével**. |
| 16 | + |
| 17 | +A fejlesztés során alkalmazott MI eszközök: |
| 18 | + |
| 19 | +- **GitHub Copilot Chat (Claude Haiku 4.5)** — kódgeneráláshoz, tesztek írásához, hibák javításához |
| 20 | +- **Claude Sonnet 4.6** — tervezéshez, architektúra döntésekhez, prompt íráshoz és hibakereséshez |
| 21 | + |
| 22 | +A projekt célja, hogy minél több különböző tesztelési megközelítést alkalmazzunk ugyanazon |
| 23 | +alkalmazáson, és értékeljük azok hatékonyságát LLM-asszisztált fejlesztési környezetben. |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## A megvalósított rendszer |
| 28 | + |
| 29 | +### Tech stack |
| 30 | + |
| 31 | +| Réteg | Technológia | |
| 32 | +|---|---| |
| 33 | +| Backend | ASP.NET Core Web API, .NET 8, SQLite, EF Core | |
| 34 | +| Frontend | React + TypeScript + Vite, Bootstrap | |
| 35 | +| Tesztelés (backend) | xUnit, Moq, FluentAssertions, FsCheck, RestSharp | |
| 36 | +| Tesztelés (frontend) | Vitest, React Testing Library, Playwright | |
| 37 | +| Terheléstesztelés | k6 | |
| 38 | +| IDE | Visual Studio 2022 (backend), VS Code (frontend) | |
| 39 | + |
| 40 | +### Solution struktúra |
| 41 | + |
| 42 | +``` |
| 43 | +Tessera/ |
| 44 | +├── Tessera.Api/ ← ASP.NET Core Web API |
| 45 | +├── Tessera.Core/ ← Domain modellek, interfészek (pure C#) |
| 46 | +├── Tessera.Data/ ← EF Core + SQLite, repository implementációk |
| 47 | +├── Tessera.Tests.Unit/ ← xUnit, Moq, FluentAssertions, FsCheck |
| 48 | +├── Tessera.Tests.Integration/ ← WebApplicationFactory + RestSharp |
| 49 | +└── load-tests/ ← k6 terheléstesztek |
| 50 | + └── habits-load-test.js |
| 51 | +
|
| 52 | +tessera-frontend/ ← React + TypeScript + Vite + Bootstrap |
| 53 | +├── src/components/__tests__/ ← Vitest + React Testing Library |
| 54 | +└── e2e/ ← Playwright E2E tesztek |
| 55 | +``` |
| 56 | + |
| 57 | +### Domain |
| 58 | + |
| 59 | +- **Habit:** Id (Guid), Name, Description?, Color (hex), CreatedAt |
| 60 | +- **HabitCompletion:** Id (Guid), HabitId, Date (DateOnly) |
| 61 | +- **Streak:** egymást követő teljesített napok sorozata |
| 62 | +- **Unique constraint:** (HabitId, Date) — egy napot csak egyszer lehet teljesíteni |
| 63 | + |
| 64 | +--- |
| 65 | + |
| 66 | +## A projekt beüzemelése |
| 67 | + |
| 68 | +### EF Core migrations — hiányzó Design csomag |
| 69 | + |
| 70 | +A `Microsoft.EntityFrameworkCore.Design` csomagot a `Tessera.Data` projektbe telepítettük |
| 71 | +(ahol a `DbContext` él), de a `dotnet ef` eszköz a startup projekten — vagyis a |
| 72 | +`Tessera.Api`-n — keresztül dolgozik, és ott is elvárja ugyanezt a csomagot. A Copilot |
| 73 | +ezt nem jelezte előre a kód generálásakor, a hiba csak a migrációs parancs futtatásakor |
| 74 | +derült ki. Megoldás: a `Microsoft.EntityFrameworkCore.Design` csomag telepítése a |
| 75 | +`Tessera.Api` projektbe is. |
| 76 | + |
| 77 | +**Tanulság:** Az EF Core tooling és a projekt referencia struktúra közötti összefüggést |
| 78 | +a Copilot nem kezeli proaktívan, a `.csproj` fájlokat és a NuGet függőségeket mindig |
| 79 | +kritikusan kell ellenőrizni. |
| 80 | + |
| 81 | +### CustomWebApplicationFactory — in-memory SQLite kapcsolat életciklusa |
| 82 | + |
| 83 | +A `CustomWebApplicationFactory` első Copilot-generált verziója nem működött: a tesztek |
| 84 | +500-as hibával buktak el. A probléma gyökere az volt, hogy az in-memory SQLite adatbázis |
| 85 | +azonnal megsemmisül, amint a kapcsolat bezárul, ugyanis a Copilot a `DbContext` |
| 86 | +regisztrációján belül hozta létre a kapcsolatot, amely így rövid életű volt. |
| 87 | + |
| 88 | +A helyes megoldás: a `SqliteConnection`-t a factory konstruktorában kell megnyitni, |
| 89 | +és `Singleton`-ként kell regisztrálni a DI konténerbe, hogy a teljes tesztelési |
| 90 | +munkamenet alatt életben maradjon. Emellett az összes `DbContext`-hez kapcsolódó |
| 91 | +DI regisztrációt el kellett távolítani, és egy |
| 92 | +`ResetDatabase()` metódust kellett bevezetni, amelyet minden tesztosztály konstruktora |
| 93 | +hív meg a tiszta állapot garantálása érdekében. |
| 94 | + |
| 95 | +A Copilot célzott javító prompttal sem generálta le a helyes megoldást, |
| 96 | + a javítás manuális beavatkozást igényelt. |
| 97 | + |
| 98 | +--- |
| 99 | + |
| 100 | +## Tesztelési fázisok |
| 101 | + |
| 102 | +### Phase 1 — Unit tesztek (xUnit + Moq + FluentAssertions) |
| 103 | + |
| 104 | +A unit tesztek a `StreakCalculator` és `StatisticsService` osztályokat fedik le. |
| 105 | +A tesztek Moq-kal mockolt függőségeket használnak, és FluentAssertions |
| 106 | +segítségével ellenőrzik az elvárt viselkedést. |
| 107 | + |
| 108 | +**Tanulság 1 — Duplikált dátumok kezelése:** |
| 109 | +A Copilot a `CalculateLongestStreak` implementációjában nem kezelte helyesen a duplikált |
| 110 | +dátumokat. Ha ugyanaz a nap kétszer szerepelt a completion listában, a streak hibásan |
| 111 | +számolódott. Célzott javító prompttal, amelyben pontosan leírtam az elvárt viselkedést |
| 112 | +és egy konkrét ellenpéldát, a hiba megoldható volt. |
| 113 | + |
| 114 | +Utólag azonban kiderült, hogy ez a védelem dead code: az adatbázis szintű |
| 115 | +`(HabitId, Date)` unique constraint, illetve az API szintű validáció (400-as válasz |
| 116 | +duplikált completion kísérletekor) együttesen garantálják, hogy a `StreakCalculator` |
| 117 | +soha nem kap duplikált dátumokat tartalmazó listát. A duplikált-dátum ág ezért |
| 118 | +production-ban elérhetetlen kód, és az azt lefedő tesztek valójában nem éles |
| 119 | +viselkedést tesztelnek. Ez architekturális tanulság: ha a rendszer több rétegben is |
| 120 | +véd ugyanazon feltétel ellen, a belső réteg védelme feleslegessé válhat. |
| 121 | + |
| 122 | +**Tanulság 2 — A `GetCompletionRate` visszatérési értékének értelmezése:** |
| 123 | +A `StatisticsService.GetCompletionRate` metódus 0.0–1.0 arányban adja vissza az |
| 124 | +eredményt (nem 0–100 százalékban), ahogy a dokumentációja is leírja. Ennek ellenére |
| 125 | +a Copilot által generált tesztek 100.0-t vártak el 1.0 helyett. A hiba csak a |
| 126 | +tesztek futtatásakor derült ki. Tanulság: a visszatérési értékek skáláját explicit |
| 127 | +módon kell megadni a promptban, különben a Copilot a "természetesebb" százalékos |
| 128 | +formátumot feltételezi. |
| 129 | + |
| 130 | +--- |
| 131 | + |
| 132 | +### Phase 2 — Integrációs tesztek (WebApplicationFactory) |
| 133 | + |
| 134 | +Az integrációs tesztek `WebApplicationFactory`-val, in-memory SQLite adatbázissal |
| 135 | +futnak. Minden tesztosztály konstruktorában `ResetDatabase()` hívás garantálja a |
| 136 | +tiszta DB állapotot (*lásd feljebb a projekt beütemezésénél*). |
| 137 | + |
| 138 | +**Tanulság 3 — Az integrációs tesztek olyan hibákat fedtek fel, amelyek unit tesztekkel |
| 139 | +nem foghatók meg:** |
| 140 | +A `CompletionsController` `Delete` metódusa hibásan volt implementálva: |
| 141 | +`GetByHabitIdAndDateAsync`-t hívott `DateOnly.MinValue`-val az ID alapú törlés helyett. |
| 142 | +A Copilot valószínűleg a GET végpont logikájából indult ki (ahol dátum alapú |
| 143 | +keresés teljesen helyes), és ezt a mintát vitte át a Delete metódusba is, DateOnly.MinValue-t |
| 144 | +használva placeholderként. A kód lefordul, unit teszttel nem fogható meg, mivel a mock nem |
| 145 | +ellenőrzi a paramétereket, csak a hívás tényét. Az integrációs teszt fedte fel a hibát: valódi |
| 146 | +adatbázis ellen futva a MinValue-val indított keresés nem talált rekordot, a törlés nem történt |
| 147 | +meg, a teszt elbukott. |
| 148 | + |
| 149 | +--- |
| 150 | + |
| 151 | +### Phase 3 — API tesztek (RestSharp) |
| 152 | + |
| 153 | +A RestSharp API tesztek valódi futó szerver ellen dolgoznak. Első kísérletkor az API-t |
| 154 | +F5-tel (Debug módban) indítottam el, majd megpróbáltam párhuzamosan futtatni a |
| 155 | +teszteket, ezt viszont a Visual Studio nem engedte. A megoldás: Ctrl+F5 |
| 156 | +(Start Without Debugging), amely a szervert a háttérben indítja el anélkül, hogy a |
| 157 | +debug folyamat lefoglalná a Visual Studio-t. |
| 158 | + |
| 159 | +--- |
| 160 | + |
| 161 | +### Phase 4 — Property-based tesztek (FsCheck) |
| 162 | + |
| 163 | +A FsCheck tesztek a `Tessera.Tests.Unit` projektbe kerültek, `FsCheck.Xunit` csomaggal, |
| 164 | +a meglévő 25 xUnit teszt mellé. |
| 165 | + |
| 166 | +A property-based tesztek a következő invariánsokat ellenőrzik véletlenszerűen generált |
| 167 | +bemeneten: |
| 168 | + |
| 169 | +- `CalculateLongestStreak` eredménye mindig >= 0 és <= a distinct dátumok száma |
| 170 | +- Duplikált dátumok hozzáadása nem változtatja meg a longest streak értékét |
| 171 | +*(lásd Tanulság 1, ez az invariáns production-ban elérhetetlen állapotot fed le)* |
| 172 | +- Teljesen egymást követő dátumsorozatnál a streak egyenlő a distinct dátumok számával |
| 173 | +- `CalculateCurrentStreak` eredménye mindig <= `CalculateLongestStreak` ugyanarra a bemenetre |
| 174 | +- Ha nincs mai vagy tegnapi completion, a current streak mindig 0 |
| 175 | +- `GetCompletionRate` eredménye mindig >= 0.0 érvényes bemenetre |
| 176 | +- Ha a tartományon kívüli dátumok szerepelnek, a completion rate 0.0 |
| 177 | + |
| 178 | +**A property-based tesztek cross-method invariánsokat is képesek ellenőrizni:** |
| 179 | +Az xUnit tesztekkel nehéz természetesen kifejezni azt, hogy `CurrentStreak <= LongestStreak` |
| 180 | +minden lehetséges bemenetre. FsCheck-kel ez egyetlen property, amely automatikusan |
| 181 | +több száz véletlenszerű esetet ellenőriz, és képes ellenpéldát generálni, ha az invariáns |
| 182 | +megsérül. |
| 183 | + |
| 184 | +--- |
| 185 | + |
| 186 | +### Phase 5 — UI komponens tesztek (Vitest + React Testing Library) |
| 187 | + |
| 188 | +A frontend tesztek a három prop-alapú komponenst fedik le: `CheckInButton`, |
| 189 | +`StatisticsPanel`, `CalendarGrid`. A `HabitCard` és `HabitList` komponensek (amelyek |
| 190 | +API hívásokat végeznek) szándékosan kimaradtak, ezeket az E2E tesztek fedik le. |
| 191 | + |
| 192 | +**Tanulság 4 — A `vitest/config` import szükséges a `vite.config.ts`-ben:** |
| 193 | +Ha a Vitest `test` konfigurációs blokkot a `vite.config.ts`-be helyezzük el, |
| 194 | +TypeScript hibát kapunk, mert a `vite` csomag `defineConfig`-ja nem ismeri a `test` |
| 195 | +mezőt. A helyes megoldás: `import { defineConfig } from 'vitest/config'` — ez |
| 196 | +re-exportálja a Vite `defineConfig`-ot, de kiegészíti a Vitest típusokkal. |
| 197 | +A Copilot ezt nem javasolta, saját utánajárás kellett hozzá. |
| 198 | + |
| 199 | +**Tanulság 5 — Az explicit TypeScript típusok fontossága tesztfájlokban:** |
| 200 | +A Copilot a tesztfájlokban `any[]`-t használt a completion tömbök típusaként. |
| 201 | +Ez TypeScript hibát okozott, mivel a komponens `HabitCompletion[]`-t vár. |
| 202 | +Az importot és a típusannotációt explicit módon kellett megadni. |
| 203 | + |
| 204 | +**A komponens tesztelhetőség és az architektúra kapcsolata:** |
| 205 | +A három könnyen tesztelhető komponens (`CheckInButton`, `StatisticsPanel`, |
| 206 | +`CalendarGrid`) mind tisztán prop-alapú, nincsen bennük API hívás vagy mellékhatás. |
| 207 | +A nehezen tesztelhető komponensek (`HabitCard`, `HabitList`) ezzel szemben |
| 208 | +`useEffect`-ben végeznek fetch hívásokat. Ez megerősíti azt az architektúrális |
| 209 | +elvet, hogy az üzleti logikát és az adatlekérést érdemes elválasztani a |
| 210 | +megjelenítési rétegtől, a separation of concerns nemcsak a kód minőségét |
| 211 | +javítja, hanem a tesztelhetőséget is. |
| 212 | + |
| 213 | +--- |
| 214 | + |
| 215 | +### Phase 6 — E2E tesztek (Playwright) |
| 216 | + |
| 217 | +A Playwright tesztek a teljes stacket fedik le valódi böngészőben: Chromium, |
| 218 | +Firefox és WebKit. A tesztek futtatásához mindkét szervernek élnie kell: |
| 219 | +a Vite dev szervernek (port 5173) és a Tessera.Api-nak (port 7184). |
| 220 | + |
| 221 | +A tesztek az alábbi felhasználói folyamatokat ellenőrzik: |
| 222 | + |
| 223 | +- Az alkalmazás betölt és a navbar látható |
| 224 | +- Az "New Habit" gombra kattintva megjelenik az űrlap |
| 225 | +- Új habit létrehozható névvel és színnel |
| 226 | +- A "Check in" gomb megnyomásával a completion regisztrálódik, az "Undo" gomb jelenik meg |
| 227 | +- A habit kártyára kattintva a részletező oldalra navigál, ahol a statisztikák láthatók |
| 228 | + |
| 229 | +**Tanulság 6 — A Playwright szintaxis eltér a Vitest szintaxisától:** |
| 230 | +A Copilot a `habits.spec.ts`-ben `describe()` blokkot generált a tesztek köré, |
| 231 | +amely Vitest-es szintaxis. A Playwright saját `test.describe()` függvényt használ, |
| 232 | +a sima `describe` nem létezik a Playwright kontextusában, és futásidejű |
| 233 | +`ReferenceError`-t okoz. A javítás egyszerű volt, de rámutat arra, hogy a Copilot |
| 234 | +nem mindig veszi figyelembe, hogy melyik tesztelési keretrendszer aktív. |
| 235 | + |
| 236 | +**Tanulság 7 — WebKit és self-signed SSL tanúsítvány összeférhetetlensége:** |
| 237 | +A tesztek kezdetben csak WebKit-ben buktak el `"Load failed"` hibával, miközben |
| 238 | +Chromium és Firefox rendben futott. A probléma gyökere: az ASP.NET Core fejlesztői |
| 239 | +szerver self-signed HTTPS tanúsítványt használ, amelyet a WebKit nem fogad el |
| 240 | +automatikusan, ellentétben a másik két böngészővel. A megoldás az |
| 241 | +`ignoreHTTPSErrors: true` beállítás a `playwright.config.ts` `use` blokkjában, |
| 242 | +amely minden böngészőre érvényes, és nem igényel backend módosítást. |
| 243 | + |
| 244 | +**Tanulság 8 — Flaky tesztek hálózati függőség esetén:** |
| 245 | +Az egyik Firefox teszt időnként `NS_ERROR_CONNECTION_REFUSED` hibával bukott el, |
| 246 | +annak ellenére, hogy a Vite szerver futott. Ez flaky viselkedés: a teszt újrafuttatásra |
| 247 | +azonnal zöld lett. Az ilyen instabilitás jellemző E2E teszteknél, ahol a tesztek |
| 248 | +valódi hálózati hívásokra támaszkodnak. Megoldás lehet `webServer` auto-start |
| 249 | +konfiguráció a `playwright.config.ts`-ben, amely garantálja, hogy a szerver |
| 250 | +ténylegesen elérhető mielőtt a tesztek elindulnak. |
| 251 | + |
| 252 | +--- |
| 253 | + |
| 254 | +### Phase 7 — Terheléstesztek (k6) |
| 255 | + |
| 256 | +A terheléstesztek a projekt utolsó tesztelési fázisát alkotják. Az előző hat fázis |
| 257 | +a helyes működést ellenőrizte különböző absztrakciós szinteken; a k6 fázis ezzel |
| 258 | +szemben azt vizsgálja, hogy az API egyidejű terhelés alatt is teljesíti-e a |
| 259 | +válaszidő-elvárásokat. |
| 260 | + |
| 261 | +#### Eszköz és telepítés |
| 262 | + |
| 263 | +A k6 önálló, Go-alapú bináris, nem Node.js csomag, nem integrálódik a meglévő |
| 264 | +`package.json`-ba, és nem igényel futtatókörnyezetet a tesztek végrehajtásához. |
| 265 | + |
| 266 | +A tesztek futtatásának előfeltétele, hogy a `Tessera.Api` élőben fusson |
| 267 | +(`https://localhost:7184`) — ugyanúgy, mint a RestSharp teszteknél: |
| 268 | +a szervert Ctrl+F5-tel kell indítani a Visual Studióban. |
| 269 | + |
| 270 | +#### Terhelési profil |
| 271 | + |
| 272 | +A teszt három szakaszból állt, összesen 50 másodperc alatt: |
| 273 | + |
| 274 | +| Szakasz | Időtartam | Virtuális felhasználók | |
| 275 | +|---|---|---| |
| 276 | +| Ramp-up | 10 s | 0 → 10 VU | |
| 277 | +| Steady state | 30 s | 10 VU (állandó) | |
| 278 | +| Ramp-down | 10 s | 10 → 0 VU | |
| 279 | + |
| 280 | +#### Tesztforgatókönyv |
| 281 | + |
| 282 | +Minden virtuális felhasználó iterációnként az alábbi szekvenciát hajtja végre: |
| 283 | + |
| 284 | +1. `GET /api/habits` — a teljes habit lista lekérése |
| 285 | + - Ellenőrzés: HTTP 200, válaszidő < 500 ms |
| 286 | +2. Ha a lista nem üres, az első elem `Id` mezőjével: `GET /api/habits/{id}/statistics` |
| 287 | + - Ellenőrzés: HTTP 200, válaszidő < 500 ms, a válasz tartalmazza a `CurrentStreak` mezőt |
| 288 | +3. 1 másodperc gondolkodási idő (think time) az iteráció végén |
| 289 | + |
| 290 | +#### Threshold-ok (pass/fail kritériumok) |
| 291 | + |
| 292 | +```javascript |
| 293 | +thresholds: { |
| 294 | + http_req_duration: ['p(95)<500'], |
| 295 | + http_req_failed: ['rate<0.01'], |
| 296 | +} |
| 297 | +``` |
| 298 | + |
| 299 | +A kérések 95%-a 500 ms alatt teljesülése és a hibaarány 1% alatt maradása jelenti a sikeres |
| 300 | +futást. |
| 301 | + |
| 302 | +#### SSL kezelés |
| 303 | + |
| 304 | +Az ASP.NET Core fejlesztői szerver self-signed tanúsítványt használ — ugyanaz a |
| 305 | +probléma, amellyel a Playwright WebKit teszteknél is szembesültünk. k6-ban a |
| 306 | +megoldás az `insecureSkipTLSVerify: true` opció az egyes `http.get` hívásoknál, |
| 307 | +nem a globális konfigurációban. |
| 308 | + |
| 309 | +**Tanulság 9 — A k6 tooling jellege alapvetően különbözik a többi tesztelési eszköztől:** |
| 310 | + |
| 311 | +A projekt minden korábbi tesztelési eszköze (xUnit, Vitest, Playwright) a |
| 312 | +fejlesztői ökoszisztémába (NuGet, npm) integrált csomag volt. A k6 ezzel szemben |
| 313 | +önálló rendszerbináris, amelyet külön kell telepíteni és a PATH-hoz adni. Ez azt |
| 314 | +jelenti, hogy a `winget install` sikere után a terminált újra kell indítani, és a |
| 315 | +`k6` parancs elérhetőségét explicit módon kell ellenőrizni, a Copilot ezt a |
| 316 | +kontextusfüggő operációs rendszer-szintű lépést nem tudja kezelni. |
| 317 | + |
| 318 | +**Tanulság 10 — A PascalCase mezőnevek nem magától értetődők JavaScript kontextusban:** |
| 319 | +A k6 tesztek JavaScript környezetben futnak, ahol a konvenció általában camelCase. |
| 320 | +A Tessera API azonban C# konvenciókat követ, és PascalCase neveket szerializál |
| 321 | +(`habit.Id`, `habit.Name`, nem `habit.id`). A Copilotnak a helyes névhasználatot a promptban |
| 322 | +explicit módon kellett specifikálni. |
| 323 | + |
| 324 | +**Tanulság 11 — A cold start torzítja a terhelésteszt eredményeit:** |
| 325 | +A futás során 3 check bukott el az `response time < 500ms` kritériumon, miközben |
| 326 | +a p(95) csupán 16.31 ms volt, ez látszólagos ellentmondás. A max=2.21s-os kiugró |
| 327 | +az ASP.NET Core JIT-fordításának és az EF Core kapcsolat első inicializálásának |
| 328 | +együttes hatása: a ramp-up szakasz legelső kérései lassabbak, mert a runtime ekkor |
| 329 | +fordítja le a releváns kódot és nyitja meg az SQLite kapcsolatot. Éles terhelési |
| 330 | +teszteknél ezt a hatást általában warm-up iterációkkal szokás eliminálni, a |
| 331 | +fejlesztői környezetben ez a viselkedés azonban |
| 332 | +elfogadható és nem meglepő. |
| 333 | + |
| 334 | +**Mérési eredmények:** |
| 335 | + |
| 336 | +Mindkét threshold teljesült: a 95. percentilis válaszidő (16.31 ms) jóval az 500 ms-os |
| 337 | +küszöb alatt maradt, hibás kérés pedig egyáltalán nem volt. A 3 failed check az |
| 338 | +`response time < 500ms` ellenőrzésnél keletkezett a cold start hatására. |
| 339 | +A steady state szakaszban ilyen kiugró nem fordult elő. |
| 340 | + |
| 341 | +--- |
| 342 | + |
| 343 | +## A névválasztásról |
| 344 | + |
| 345 | +A projekt neve **Tessera** — latin szó, jelentése: kis négyzet, csempe, dominókő. |
| 346 | +A domino effect a szokásépítés metaforája; a naptárnézet kis négyzetei vizuálisan |
| 347 | +is utalnak a névre. Tagline: *"Your habits, one tile at a time."* |
| 348 | + |
| 349 | +--- |
| 350 | + |
| 351 | +## Összefoglalás |
| 352 | + |
| 353 | +| Tesztelési módszer | Eszköz | Lefedett terület | |
| 354 | +|---|---|---| |
| 355 | +| Unit tesztek | xUnit + Moq + FluentAssertions | StreakCalculator, StatisticsService | |
| 356 | +| Integrációs tesztek | WebApplicationFactory | API végpontok, DB műveletek | |
| 357 | +| API tesztek | RestSharp | Valódi szerver ellen | |
| 358 | +| Property-based tesztek | FsCheck | Streak és statisztika invariánsok | |
| 359 | +| UI komponens tesztek | Vitest + RTL | CheckInButton, StatisticsPanel, CalendarGrid | |
| 360 | +| E2E tesztek | Playwright | Teljes felhasználói folyamatok, 3 böngésző | |
| 361 | +| Terheléstesztek | k6 | GET /api/habits, GET /api/habits/{id}/statistics; p(95)=16 ms, 0% hiba | |
| 362 | + |
| 363 | + |
| 364 | +Az LLM eszközök jelentősen felgyorsítják a tesztek generálását, de folyamatos |
| 365 | +emberi felügyeletet igényelnek. A leggyakoribb hibamintázat: a Copilot érti az általános |
| 366 | +esetet, de az edge case-eknél pontosabb promptot vagy manuális javítást igényel. A projekt beüzemelési nehézségei (EF Core Design csomag, in-memory SQLite kapcsolat életciklusa) |
| 367 | +szintén rávilágítanak arra, hogy a Copilot a konfigurációs és tooling jellegű problémákat |
| 368 | +kevésbé kezeli megbízhatóan, mint a kódgenerálást. |
| 369 | + |
| 370 | +A projekt egy architekturális tanulsággal is szolgált: a duplikált dátumok kezelése |
| 371 | +a `StreakCalculator`-ban utólag dead code-nak bizonyult, mivel az adatbázis és az API |
| 372 | +réteg együttesen megakadályozzák, hogy ilyen állapot egyáltalán előálljon. Ez |
| 373 | +rámutat arra, hogy LLM-asszisztált fejlesztésben — ahol a rétegek egymástól |
| 374 | +függetlenül születnek — különösen fontos a rendszer egészének átlátása: a részek |
| 375 | +önmagukban helyesek lehetnek, miközben együttesen ellentmondást alkotnak. |
| 376 | + |
| 377 | +**Szerző:** Várhegyi Melinda |
0 commit comments