Przejdź do głównej treści

Frameworki kodowe

Testowanie scenariuszami

Zbuduj element, uruchom akcje i sprawdź każdą wartość i zapis.

Co zawiera scenariusz

Scenariusz to plik JSON w scenarios/. Buduje element z danych wejściowych, uruchamia akcje po kolei i sprawdza wyniki. Manifest wymienia każdy plik scenariusza, a każdy plik zawiera jeden scenariusz.

scenarios/heal.json
{
  "id": "heal-after-damage",
  "framework": "keeper",
  "parameters": { "name": "Mira", "max_hp": 10 },
  "expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10 },
  "actions": [
    {
      "action": "hurt",
      "parameters": { "amount": 6 },
      "expectedWrites": [{ "op": "ledger.add", "key": "hp", "value": -6 }]
    },
    {
      "action": "heal",
      "parameters": { "amount": 9 },
      "expectedWrites": [{ "op": "ledger.set", "key": "hp", "value": 10 }]
    },
    { "action": "heal", "parameters": { "amount": 3 }, "expectedWrites": [] }
  ]
}
  1. Wiersze 4-5 Zbuduj element z tych danych wejściowych i sprawdź jego wartości początkowe.
  2. Wiersz 6 actions wymienia kroki do uruchomienia, po kolei.
  3. Wiersz 10 Dokładne zapisy, które krok musi wykonać.
  4. Wiersz 17 Brak zapisów: nic się nie zmieniło.
PoleZnaczenie
idNazwa scenariusza.
frameworkId frameworka do zbudowania.
parametersDane wejściowe, z którymi ma być zbudowany.
expectedValuesKażda zapisana wartość tuż po zbudowaniu.
expectedChildrenWartości każdego miejsca podrzędnego.
actionsKroki do uruchomienia, najwyżej 32 na scenariusz. Każdy ma akcję, jej parametry i expectedWrites.
ledgerSprawdzenia wartości pochodnych.
listsWypełnia listę wpisami, według id presetu.
expectedListsWpisy, które każda lista zawiera na końcu, według id presetu.
poolRollsZapisane rzuty dla puli używającej metody roll, według identyfikatora puli. Zobacz Rzucane wyniki.
contentWpisy treści przypięte do zbudowanego Elementu (kind, entryId, name i parameters), scalane z wydaniem tak jak przypięcia postaci.

Krok może używać dodatkowych pól:

Pole krokuZnaczenie
chooseDla akcji listy: wpis, który gracz wybiera dla każdych danych wejściowych ContentRef, według id presetu.
expectedRefusalOdmowa, którą krok musi zakończyć. Taki krok nie oczekuje wtedy żadnych zapisów.
expectedValuesAfterZapisane i pochodne wartości po kroku. Wartości pochodne są najpierw przeliczane.

Zapisy

expectedWrites wymienia po kolei każdy zapis wykonany w kroku. Użyj ledger.set dla ustawionej wartości i ledger.add dla dodanej ilości. Krok, który nic nie zmienia, nie wymienia zapisów, więc testowany jest też warunek pomijający zapis.

Jeśli prawdziwe zapisy się różnią, sprawdzenie pokazuje obie listy.

"expectedWrites": [{ "op": "ledger.set", "key": "hp", "value": 9 }]
Expected ordered writes [{"op":"ledger.set","key":"hp","value":9}]; observed [{"op":"ledger.set","key":"hp","value":10}].

Wartości pochodne i elementy podrzędne

Lista ledger sprawdza funkcję ledgera. Podaje id funkcji, wartość wyjściową i wartość, którą funkcja ma zwrócić. expectedChildren sprawdza elementy podrzędne.

scenarios/new-keeper.json
  "expectedChildren": { "lamp": { "name": "Lantern", "oil": 5 } },
  1. Wiersz 17 Sprawdza elementy w miejscach podrzędnych.
scenarios/new-keeper.json
  "ledger": [{ "function": "guard", "currentValue": 0, "expected": 3 }]
  1. Wiersz 18 Wywołuje funkcję warunku z bieżącą wartością 0 i oczekuje 3.

Co trzeba pokryć

  • Każdy konstruktor, akcja i funkcja ledgera potrzebuje scenariusza.
  • Każda akcja potrzebuje co najmniej jednego kroku. Dodaj krok dla każdej gałęzi, którą chcesz sprawdzić, na przykład jeden, który zapisuje, i jeden, który nic nie zapisuje.
  • Akcja, która dodaje do listy, potrzebuje jednego kroku przyjętego i jednego kroku z expectedRefusal, cokolwiek mówi jej oferta. Krok odrzucony dowodzi, że oferta potrafi odmówić. Akcja, która tylko usuwa z listy, potrzebuje jednego kroku przyjętego.
  • Oczekiwane wartości muszą odpowiadać temu, co konstruktor naprawdę zwraca, z już zastosowanymi funkcjami ledgera.

Kroki noszą nazwę swojego scenariusza. Komunikat taki jak heal-after-damage-2 oznacza trzeci krok scenariusza heal-after-damage, bo ten numer liczy od 0. Inne komunikaty liczą kroki od 1.

Krok, który oczekuje odmowy od akcji, która nie została odrzucona, kończy się błędem. Tak samo kończy się odwrotny przypadek:

the step expects it to be refused with NOT_OFFERED
Add expectedRefusal

Akcja bez kroku kończy się błędem:

SELF_SCALAR_ACTION_SCENARIO_COVERAGE_MISSING: action keeper.hurt (Take damage) has no executable scenario steps.

Akcja listy, której brakuje kroku przyjętego lub odrzuconego, kończy się błędem:

add a step with expectedRefusal, so its refused branch is proven.
add a step whose list.add is accepted, so its accepted branch is proven.

Oczekiwane wartości różne od tych z konstruktora kończą się błędem:

Constructor output does not match its scenario.

Odmowy

Akcja listy może zostać odrzucona. Krok, który tego oczekuje, podaje kod w expectedRefusal i nie wymienia żadnych zapisów.

KodKiedy
NOT_OFFEREDWybranego wpisu nie ma wśród wpisów, które dopuszcza oferta.
ALREADY_IN_LISTLista ma już ten wpis.
LIST_FULLLista osiągnęła maksymalny rozmiar.
NOT_IN_LISTlist.remove wskazuje wpis, którego lista nie zawiera.
LIST_CAPZostałby przekroczony limit zadeklarowany przez listę.
SAME_NAMELista ma już wpis o tej nazwie.

Ten projekt potwierdza kilka z nich. Ma też krok, w którym warunek zatrzymuje akcję, więc krok nie oczekuje ani zapisów, ani odmowy.

scenarios/pack.json
{
  "id": "pack-trinkets",
  "framework": "keeper",
  "parameters": { "name": "Mira", "max_hp": 10 },
  "expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10 },
  "actions": [
    {
      "action": "pack_trinket",
      "parameters": {},
      "choose": { "trinket": "rope" },
      "expectedWrites": [{ "op": "list.add", "key": "pack", "value": "rope" }]
    },
    {
      "action": "pack_trinket",
      "parameters": {},
      "choose": { "trinket": "rope" },
      "expectedRefusal": "ALREADY_IN_LIST",
      "expectedWrites": []
    },
    {
      "action": "pack_trinket",
      "parameters": {},
      "choose": { "trinket": "anvil" },
      "expectedRefusal": "NOT_OFFERED",
      "expectedWrites": []
    },
    {
      "action": "pack_trinket",
      "parameters": {},
      "choose": { "trinket": "candle" },
      "expectedWrites": [
        { "op": "list.add", "key": "pack", "value": "candle" }
      ]
    },
    {
      "action": "pack_trinket",
      "parameters": {},
      "choose": { "trinket": "bell" },
      "expectedWrites": []
    },
    {
      "action": "unpack_trinket",
      "parameters": {},
      "choose": { "trinket": "rope" },
      "expectedWrites": [
        { "op": "list.remove", "key": "pack", "value": "rope" }
      ]
    },
    {
      "action": "unpack_trinket",
      "parameters": {},
      "choose": { "trinket": "rope" },
      "expectedRefusal": "NOT_IN_LIST",
      "expectedWrites": []
    }
  ],
  "expectedLists": { "pack": ["candle"] }
}
  1. Wiersze 7-12 Przyjęty: list.add zapisuje linę.
  2. Wiersze 13-19 Odrzucony: lista ma już linę.
  3. Wiersze 20-26 Odrzucony: oferta nie dopuszcza kowadła.
  4. Wiersze 35-40 Plecak ma już dwa wpisy, więc warunek nic nie zapisuje i nie oczekujemy odmowy.
  5. Wiersze 41-48 Usunięty: lina znika z listy.
  6. Wiersze 49-55 Odrzucony: liny nie ma już na liście.
  7. Wiersz 57 Plecak kończy ze świecą jako jedynym wpisem.

Uruchamianie

Sprawdź i wyświetl w The Forge kompiluje projekt i uruchamia każdy scenariusz. Nic nie jest publikowane i żadna działająca postać się nie zmienia.

Dalej