A tesztgenerátor egy kurzusspecifikus szoftver, amely automatikusan előállítja egy gyakorlófeladat tesztjeit. Ezt úgy végzi, hogy a feladat JSON-formátumú teszteseteit a kurzus nyelvén írt tesztekké alakítja.
A tesztgenerátor néhány előnye:
Általában azért futtatunk egy tesztgenerátort, hogy:
Ha új feladathoz készítünk tesztgenerátort, azzal előállíthatók a feladat tesztfájlja(i). Feltéve, hogy maga a tesztgenerátor már elkészült, az új feladat tesztjeinek előállítása (sokkal) kevesebb munkával jár, mint azok nulláról való megírása.
Ha egy feladathoz már van tesztgenerátor, újrafuttathatod, hogy frissítsd, illetve szinkronizáld a feladatot a legfrissebb kanonikus adataival. Javasoljuk, hogy ezt rendszeresen tedd meg: így ellenőrizheted, vannak-e olyan problémás tesztesetek, amelyeket frissíteni kell, vagy olyan új tesztek, amelyeket be szeretnél venni.
Kétféle kiindulópont lehetséges, amikor egy feladathoz tesztgenerátort készítesz:
Ha már vannak meglévő tesztek, úgy készítsd el a tesztgenerátort, hogy az általa előállított tesztek ne törjék el a meglévő megoldásokat.
Általánosságban a tesztfájlok kétféleképpen állíthatók elő:
Tapasztalatunk szerint a kódalapú megközelítés meglehetősen összetett tesztgenerátor-kódhoz vezet, míg a sablonalapú egyszerűbb.
A következő folyamatot javasoljuk:
tests.toml fájljában include = false jelöléssel szerepelnekA felállás legfontosabb előnye, hogy minden feladatnak saját sablonja van, ami:
Amikor a tesztgenerátort tervezed, törekedj arra, hogy:
A tesztgenerátort általában (nagyrészt) a kurzus nyelvén írják.
Bár szabadon használhatsz más nyelveket is, minden további nyelv megnehezíti a kurzus karbantartását és a hozzá való közreműködést. Ezért ahol csak lehet, a kurzus nyelvét javasoljuk használni, mert így könnyebb a karbantartás és a közreműködés.
Ha a kurzusodban van kódformázó tooling, érdemes ezt utófeldolgozási lépésként futtatni, miután renderelted a sablont.
A tesztgenerátor alapvető adatforrása egy feladat canonical-data.json fájlja.
Ezt a fájlt az exercism/problem-specifications repo definiálja, amely számos Exercism-feladat közös metaadatait tartalmazza.
Nem minden feladatnak van canonical-data.json fájlja!
Ha nincs, a teszteket manuálisan kell létrehoznod, mert a tesztgenerátornak nem lesz mivel dolgoznia.
A kanonikus adatok egy JSON-objektumban vannak definiálva.
Ez az objektum tartalmaz egy "cases" mezőt, amely a teszteseteket tartalmazza.
Ezek a tesztesetek (általában) egy az egyben megfelelnek a kurzusod tesztjeinek.
Minden tesztesetnek több tulajdonsága van, amelyek közül a leírás, a property, a bemeneti érték(ek) és az elvárt érték a legfontosabb. Íme egy (részleges) példa a leap feladat canonical-data.json fájljára:
{
"exercise": "leap",
"cases": [
{
"uuid": "6466b30d-519c-438e-935d-388224ab5223",
"description": "year not divisible by 4 in common year",
"property": "leapYear",
"input": {
"year": 2015
},
"expected": false
},
{
"uuid": "4fe9b84c-8e65-489e-970b-856d60b8b78e",
"description": "year divisible by 4, not divisible by 100 in leap year",
"property": "leapYear",
"input": {
"year": 1996
},
"expected": true
}
]
}
A tesztgenerátor fő feladata, hogy ezt a JSON-adatot kurzusspecifikus tesztekké alakítsa. Így fordulhat le a fenti JSON Nim-tesztkóddá:
import unittest
import leap
suite "Leap":
test "year not divisible by 4 in common year":
check isLeapYear(2015) == false
test "year divisible by 4, not divisible by 100 in leap year":
check isLeapYear(1996) == true
A canonical-data.json fájl szerkezete jól dokumentált, és JSON-séma definíció is tartozik hozzá.
Egyes feladatok beágyazást használnak a kanonikus adataikban.
Ez azt jelenti, hogy egy cases tömb minden eleme a következők egyike lehet:
Egy elem típusát arról ismerheted fel, hogy megvizsgálod, jelen vannak-e az adott elemtípusra jellemző mezők.
Erre valószínűleg a "cases" kulcs a legjobb mód, mert ez csak a tesztesetcsoportokban fordul elő.
Íme egy példa beágyazott tesztesetekre:
{
"cases": [
{
"uuid": "e9c93a78-c536-4750-a336-94583d23fafa",
"description": "data is retained",
"property": "data",
"input": {
"treeData": ["4"]
},
"expected": {
"data": "4",
"left": null,
"right": null
}
},
{
"description": "insert data at proper node",
"cases": [
{
"uuid": "7a95c9e8-69f6-476a-b0c4-4170cb3f7c91",
"description": "smaller number at left node",
"property": "data",
"input": {
"treeData": ["4", "2"]
},
"expected": {
"data": "4",
"left": {
"data": "2",
"left": null,
"right": null
},
"right": null
}
}
]
}
]
}
Ha a kurzusod nem támogatja a tesztek csoportosítását, akkor:
cases hierarchiát, illetve ki kell laposítanod, hogy csak a legbelső (levél) tesztesetek maradjanakA tesztesetek input és expected kulcsainak tartalma nagyon változatos.
A legtöbb esetben skaláris értékek (például számok, Boolean-ok vagy stringek) vagy egyszerű objektumok.
Előfordulhat azonban, hogy összetettebb értékekkel találkozol, amelyek valószínűleg némi előfeldolgozást igényelnek: ilyenek például a pszeudokódban megadott lambdák, a tanuló kódján végrehajtandó műveletek listái és hasonlók.
A teszteseteknek van egy opcionális scenarios mezőjük.
A tesztgenerátor ezt a mezőt arra használhatja, hogy bizonyos teszteseteket külön kezeljen.
A leggyakoribb eset bizonyos teszttípusok figyelmen kívül hagyása, például a "unicode" forgatókönyvvel jelölt teszteké, mert elképzelhető, hogy a kurzusod nyelve nem támogatja a Unicode-ot.
A forgatókönyvek teljes listája itt található.
Néhány lehetőség kínálkozik a canonical-data.json fájlok beolvasására:
problem-specifications repóból (pl. https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/leap/canonical-data.json).problem-specifications repót Git-almodulként hozzáadod a kurzus repójához.configlet gyorsítótárából.
A hely a felhasználó rendszerétől függ, de a configlet info -o -v d | head -1 | cut -d " " -f 5 paranccsal programozottan is megkaphatod a helyét.Ha a kurzusod szeretne néhány további, kurzusspecifikus tesztesetet hozzáadni (amelyek nem szerepelnek a kanonikus adatokban), az egyik lehetőség egy additional-test-cases.json fájl létrehozása, amelyet a tesztgenerátor összefűzhet a canonical-data.json fájllal, mielőtt renderelésre átadná a sablonnak.
A használandó sablonmotor valószínűleg kurzusspecifikus. Ideális esetben a sablonjaid a lehető legegyszerűbbek legyenek, szóval ne törődj a kóddublázással meg hasonlókkal.
Maguk a sablonok a tesztgenerátortól kapják az adataikat, és a generátor ezeken végigiterálva rendereli ki a sablonokat.
Hogy a sablonok egyszerűek maradjanak, hasznos lehet egy kis előfeldolgozást végezni a tesztgenerátor oldalán, vagy definiálni néhány „szűrőt”, illetve bármilyen bővítési mechanizmust, amit a sablonjaid támogatnak.
A configlet az elsődleges kurzuskarbantartó eszköz, amellyel többek között:
bin/configlet create --practice-exercise <slug> parancsottests.toml fájlját: futtasd a bin/configlet sync --tests --update --exercise <slug> parancsotÍgy a configlet kiválóan kombinálható a tesztgenerátorral, és igazán hatékony munkafolyamatokat tesz lehetővé.
Szeretnéd, ha a tesztgenerátor használata egyszerre lenne könnyű és hatékony. Ehhez egy vagy több szkriptfájl létrehozását javasoljuk.
Szabadon választhatsz olyan szkriptfájl-formátumot, amelyik a legjobban illik a kurzusodhoz. A shell-szkriptek és a PowerShell-szkriptek gyakori, jól működő választások.
Íme egy példa egy shell-szkriptre, amely a configlet és egy tesztgenerátor kombinálásával gyorsan felállítja egy új feladat vázát:
bin/fetch-configlet
bin/configlet create --practice-exercise <slug>
path/to/test-generator <slug>
Mielőtt elkezdenéd a tesztgenerátor építését, érdemes megnézned néhány létező tesztgenerátort, hogy érezd, más kurzusok hogyan valósították meg őket:
Ha kérdéseid vannak, azokra a fórum a legjobb hely, ahol választ kaphatsz. A Rust és a JavaScript tesztgenerátorairól szóló fórumos beszélgetések szintén hasznosak lehetnek.
Javasoljuk, hogy a tesztgenerátort fokozatosan építsd fel, egy minimális életképes termékkel kezdve.
Egy legegyszerűbb változat beolvassa egy feladat canonical-data.json fájlját, és egyszerűen átadja az adatokat a sablonnak.
Kezdd egyetlen feladattal, lehetőleg egy egyszerűvel, mint például a leap.
Csak amikor az már működik, akkor adj hozzá fokozatosan további feladatokat.
És próbáld a tesztgenerátort a lehető legegyszerűbben tartani.
Ideális esetben egy közreműködő csak beilleszt vagy módosít egy meglévő sablont anélkül, hogy meg kellene értenie, hogyan működik belülről a tesztgenerátor.
A tesztgenerátor használata és a hozzá való közreműködés kurzusspecifikus.
Keress útmutatót a kurzus README.md, CONTRIBUTING.md fájljában vagy a tesztgenerátor kódjának könyvtárában.