A tesztfuttató interfésze


A tesztfuttatóknak egyetlen feladatuk van: átveszik a megoldást, lefuttatják az összes tesztet, és szabványosított kimenetet adnak vissza. Az Exercism weboldalával való minden kapcsolattartás automatikusan történik, és nem része ennek a specifikációnak.

Futtatás

  • A tesztfuttatónak biztosítania kell egy futtatható szkriptet. További információkat a docker.md fájlban találsz.
  • A szkript három paramétert kap:
    • A feladat slugja (pl. two-fer).
    • Egy bemeneti könyvtár elérési útja (záró perjellel), amely a beküldött megoldásfájl(oka)t és a feladat bármely más fájlját tartalmazza. Ezt a könyvtárat csak olvashatónak kell tekinteni. Technikailag lehetséges írni bele, de az ideiglenes fájlokhoz (pl. források lefordításához) jobb a /tmp könyvtárat használni.
    • Egy kimeneti könyvtár elérési útja (záró perjellel). Ez a könyvtár írható.
  • A szkriptnek egy results.json fájlt kell írnia a kimeneti könyvtárba.
  • A futtatónak 0-s kilépési kóddal kell kilépnie, ha sikeresen lefutott, függetlenül a tesztek állapotától.

Engedélyezett futási idő

A tesztfuttató megoldásonként egy 20 másodperces időablakra 100% CPU-t és 3 GB memóriát kap. 20 másodperc után a folyamat leáll, és időtúllépést jelez.

Note

Erősen ajánljuk, hogy kövesd a teljesítményre vonatkozó bevált gyakorlatokról szóló dokumentumot, hogy csökkentsd az időtúllépés esélyét.

Kimeneti formátum

A results.json fájlokban az alábbi mezők támogatottak:

Legfelső szint

Verzió

kulcs: version, típus: number, jelenlét: kötelező

verzió: 1, 2, 3

Annak a specifikációnak a verziója, amelyhez ez a fájl igazodik:

  • 1: Olyan kurzusokhoz, amelyeknek a tesztfuttatója nem tud információt adni az egyes tesztekről.
  • 2: Olyan kurzusokhoz, amelyeknek a tesztfuttatója képes kiírni az egyes tesztek adatait. A tanulófeladatokkal rendelkező kurzusok minimálisan megkövetelt verziója.
  • 3: Olyan kurzusokhoz, amelyeknek a tesztfuttatója az egyes teszteket részfeladatokhoz tudja kapcsolni.

Állapot

kulcs: status, típus: string, jelenlét: kötelező

verzió: 1, 2, 3

A következő átfogó állapotok érvényesek:

  • pass: Minden teszt sikeres
  • fail: Legalább egy teszt állapota fail vagy error
  • error: Egyetlen teszt sem futott le (ez általában fordítási vagy szintaktikai hibát jelent)

Az error állapotot csak akkor használd, ha az összes teszt hibázott. Fordított nyelvek esetében ez általában annak a következménye, hogy a kód nem fordítható le. Értelmezett nyelvek esetében ez futásidejű hiba, például egy szintaktikai hiba, amely megakadályozza a fájl feldolgozását.

Üzenet

kulcs: message, típus: string, jelenlét: kötelező, ha status = error, vagy ha status = fail és version = 1

verzió: 1, 2, 3

Ha az állapot error (egyetlen teszt sem futott le helyesen), akkor a legfelső szintű message kulcsot meg kell adni. Ez mutatja meg a felhasználónak a fellépő hibát. Mivel ez az egyetlen információ, amelyet a felhasználó a hibája kiderítéséhez kap, a lehető legvilágosabbnak kell lennie:

  • Egyszerűsítsd az elérési utakat valami ilyesmire: <solution-dir>/relative/path a /full/path/to helyett, mert utóbbi zavaró, ECR-specifikus adatokat is tartalmaz
  • Ha lehetséges és indokolt, vond össze a nem a felhasználó kódjához tartozó hívási verem bejegyzéseit
  • Soha ne jeleníts meg hívási vermet kontextus nélkül (vagyis a hibaüzenet nélkül)
  • Lehetőleg ne változtasd meg a hibaüzenetet, mert így könnyebb lesz rá keresni

Rubyban szintaktikai hiba esetén a futásidejű hibát és a hívási vermet adjuk meg. Fordított nyelvek esetében a fordítási hibát kell megadni.

A legfelső szintű message érték legfeljebb 65535 karakter lehet. A tényleges maximális hossz kevesebb, ha az érték többbájtos karaktereket tartalmaz.

Ha az állapot nem error, akkor vagy állítsd az értéket null-ra, vagy hagyd el teljesen a kulcsot.

Tesztek

kulcs: tests, típus: array, jelenlét: kötelező, ha status = fail vagy status = pass

verzió: 2, 3

Ez a teszteredmények tömbje, amelyet az alábbi „Tesztenkénti” szakasz ír le.

A teszteket KELL abban a sorrendben visszaadni, ahogyan a tesztfájlban szerepelnek. A véletlenszerű sorrendben tesztelő nyelvek esetében ez azt jelentheti, hogy az eredményeket a tesztfájlban megadott sorrendnek megfelelően újra kell rendezni.

Ennek az az oka, hogy a tanulóknak csak az első hibát mutatjuk meg, ezért fontos, hogy a helyes hiba jelenjen meg. Mivel a tesztfájlban a tesztek általában TDD-szemléletben vannak sorba rendezve, és mivel a gyakorlófeladatoknál a tanulók a szerkesztőben látják a tesztfájlt, elengedhetetlen az eredményeket a tesztfájlhoz igazítani.

Tesztenkénti

Név

kulcs: name, típus: string, jelenlét: kötelező

verzió: 2, 3

Ez a teszt neve, ember által olvasható formátumban.

Tesztkód

kulcs: test_code, típus: string, jelenlét: kötelező, ha a feladat tanulófeladat

verzió: 2, 3

Tanulófeladatoknál ez KELL, hogy szerepeljen, gyakorlófeladatoknál pedig KELLENE. A követelmény különbsége abból fakad, hogy a tanulófeladatoknál a tanulók nem látják a teszteket, így a test_code megjelenítése nélkül lehetetlen lehet megoldani a feladatot, a gyakorlófeladatoknál viszont a tesztek láthatók.

Ez a tesztelt parancs törzse. Például a következő Ruby-teszt:

def test_duplicate_items_uniqs_list
  cart = ShoppingCart.new
  cart.add(:STARIC)
  cart.add(:MEDNEW)
  cart.add(:MEDNEW)
  assert_equal 'Newspaper, Rice', cart.items_list
end

esetén a test_code értékeként ezt kell visszaadni:

"cart = ShoppingCart.new
cart.add(:STARIC)
cart.add(:MEDNEW)
cart.add(:MEDNEW)
assert_equal 'Newspaper, Rice', cart.items_list"

(a sortöréseket \n helyettesíti, hogy a JSON érvényes legyen).

Állapot

kulcs: status, típus: string, jelenlét: kötelező

verzió: 2, 3

A következő tesztenkénti állapotok érvényesek:

  • pass: A teszt sikeres volt
  • fail: A teszt sikertelen volt
  • error: A teszt hibázott, azaz nem adott vissza értéket

Üzenet

kulcs: message, típus: string, jelenlét: kötelező, ha status értéke fail vagy error

verzió: 2, 3

A tesztenkénti message kulcs arra szolgál, hogy visszaadja egy fail vagy error állapotú teszt eredményeit. A lehető leginkább ember által olvashatónak kell lennie. Amit ide írsz, az megjelenik a tanulónak, amikor a tesztje nem sikerül. Ha nincs hibát jelző üzenet vagy hibaüzenet, akkor vagy állítsd az értéket null-ra, vagy hagyd el teljesen a kulcsot. Az is megengedett, hogy ide írd a tesztsorozat kimenetét. A message érték hossza nincs korlátozva.

Kimenet

kulcs: output, típus: string, jelenlét: opcionális

verzió: 2, 3

A tesztenkénti output kulcsot arra kell használni, hogy tárolja és megjelenítse mindazt, amit a felhasználó szándékosan kiír egy teszthez.

  • Minden olyan teszteredményhez csatolni kell, amely felhasználói kimenetet állít elő.
  • Csak a felhasználó által kézzel kiírt tartalom jelenjen meg, ne a tesztfuttató automatikus kimenete.
  • Vagy elkaphatod a normál módon kiírt tartalmat (pl. puts Rubyban, print Pythonban vagy Debug.WriteLine C#-ban), vagy biztosíthatsz egy metódust, amelyet a felhasználó használhat (pl. a Ruby-tesztfuttató biztosít a felhasználónak egy globálisan elérhető debug metódust, amely ugyanolyan tulajdonságokkal rendelkezik, mint a szabványos puts metódus).
  • A kimenetet 500 karakterre kell korlátozni. Ebben az esetben vagy csonkítsd a szöveget egy ilyen üzenettel: „Output was truncated. Please limit to 500 chars”, vagy adj vissza hibát, mindkettő elfogadható.

Részfeladat azonosítója

kulcs: task_id, típus: number, jelenlét: opcionális

verzió: 3

Kapcsolj egy tesztet egy adott részfeladathoz annak azonosítóján keresztül, amely a részfeladat címsorának elején szereplő szám. Csak akkor kapcsolj egy tesztet egy részfeladathoz, ha az pontosan egy részfeladathoz kapcsolható.

Jelenleg csak a tanulófeladatoknak vannak jól meghatározott részfeladatai, amelyekhez teszteket kapcsolhatsz, de ez a jövőben változhat.

Például vegyük a következő instructions.md fájlt:

# Instructions

You're going to write some code to help Lucian cook an exquisite lasagna from his favorite cook book.

## 1. Define the expected oven time in minutes

...

## 2. Calculate the remaining oven time in minutes

...

Ezek az utasítások két részfeladatot határoztak meg:

  1. Határozd meg a sütő várható idejét percben
  2. Számítsd ki a sütő hátralévő idejét percben

A results.json fájl ekkor tartalmazhat egy ilyen bejegyzést:

{
  "name": "Expected oven time in minutes",
  "status": "pass",
  "task_id": 1,
  "test_code": "Assert.Equal(40, Lasagna.ExpectedMinutesInOven());"
}

Ez a teszt most az első részfeladathoz kapcsolódik: „Határozd meg a sütő várható idejét percben”. Vegyük észre, hogy a névnek nem kell megegyeznie a részfeladat leírásával.

Többféleképpen is megvalósíthatják ezt a kurzusok:

  • Adj metaadatokat a tesztfájlban lévő tesztekhez (pl. attribútumok/annotációk/megjegyzések használatával), és a tesztfuttató olvassa be ezeket a metaadatokat a tesztek futtatásakor.
  • Tárold a tesztnév és a részfeladat-azonosító közötti megfeleltetést egy külön fájlban (például a feladat .meta/config.json fájljában), és olvaszd bele ezt az információt a generált results.json fájlba.

Példák

Az alábbiakban arra látsz példákat, hogyan nézhet ki egy érvényes results.json fájl a különböző verziókban:

v1 példa

{
  "version": 1,
  "status": "fail",
  "message": "Failed: test_answer\nExpected: 42, actual: 3"
}

v2 példa

{
  "version": 2,
  "status": "fail",
  "message": null,
  "tests": [
    {
      "name": "Test that the thing works",
      "status": "fail",
      "message": "Expected 42 but got 123123",
      "output": "Debugging information output by the user",
      "test_code": "assert_equal 42, answerToTheUltimateQuestion()"
    }
  ]
}

v3 példa

{
  "version": 3,
  "status": "fail",
  "message": null,
  "tests": [
    {
      "name": "Test that the thing works",
      "status": "fail",
      "message": "Expected 42 but got 123123",
      "output": "Debugging information output by the user",
      "test_code": "assert_equal 42, answerToTheUltimateQuestion()",
      "task_id": 1
    }
  ]
}

Felhasználói felület és felhasználói élmény

Teszthiba esetén

Amikor egy tanuló megoldása elbukik egy teszten, valami ilyesmit kell megjelenítenie:

Test Code:
  <test_code>

Test Result:
  <message>

Sikeres teszt esetén

Amikor a megoldás átmegy egy teszten, valami ilyesmit kell megjelenítenie:

Test Code:
  <test_code>

Hogyan adj metaadatokat a nyelved tesztsorozatához

Minden út Rómába vezet, és nincs előírt minta, amivel ezt el lehet érni. Eddig többféle megközelítést alkalmaztak:

  • Kézzel összeállított kiegészítő JSON-fájlok, amelyeket a tesztfuttatás ideje alatt összefésülnek a teszteredményekkel.
  • A tesztsorozat automatizált statikus elemzése, amelyet a tesztfuttatás ideje alatt összefésülnek a teszteredményekkel.
    • Ez AST-elemzéssel vagy szövegelemzéssel valósítható meg