Pular para o conteúdo principal

Code frameworks

Testando com cenários

Crie um Element, execute ações e confira cada valor e cada escrita.

O que um cenário contém

Um cenário é um arquivo JSON em scenarios/. Ele cria um Element a partir de entradas, executa ações em ordem e confere os resultados. O manifesto lista todos os arquivos de cenário, e cada arquivo contém um cenário.

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. Linhas 4-5 Crie o Element com estas entradas e confira seus valores iniciais.
  2. Linha 6 actions lista os passos a executar, em ordem.
  3. Linha 10 As escritas exatas que o passo deve fazer.
  4. Linha 17 Nenhuma escrita: nada mudou.
CampoSignificado
idO nome do cenário.
frameworkO id do Framework a criar.
parametersAs entradas usadas para criá-lo.
expectedValuesTodos os valores salvos logo após a construção.
expectedChildrenOs valores de cada espaço filho.
actionsPassos a executar, no máximo 32 por cenário. Cada um tem uma action, seus parameters e expectedWrites.
ledgerVerificações de valores derivados.
listsPreenche uma lista com entradas, pelo id do preset.
expectedListsAs entradas que cada lista tem no final, pelo id do preset.
poolRollsRolagens registradas para um pool que usa o método roll, por id do pool. Veja Valores rolados.
contentEntradas de conteúdo fixadas ao Element construído (kind, entryId, name e parameters), mescladas na versão como as fixações de um personagem.

Um passo pode usar mais campos:

Campo do passoSignificado
choosePara uma ação de lista: a entrada que o jogador escolhe para cada entrada ContentRef, pelo id do preset.
expectedRefusalA recusa com que o passo deve terminar. O passo então espera nenhuma escrita.
expectedValuesAfterValores salvos e derivados depois do passo. Os valores derivados são recalculados primeiro.

Escritas

expectedWrites lista todas as escritas que o passo faz, em ordem. Use ledger.set para um valor que foi definido e ledger.add para uma quantia que foi somada. Um passo que não muda nada não lista escritas, então a proteção que pula uma escrita também é testada.

Se as escritas reais forem diferentes, a verificação mostra as duas listas.

"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}].

Valores derivados e filhos

A lista ledger confere uma função de ledger. Ela informa o id da função, o valor de partida e o valor que deve ser retornado. expectedChildren confere os Elements filhos.

scenarios/new-keeper.json
  "expectedChildren": { "lamp": { "name": "Lantern", "oil": 5 } },
  1. Linha 17 Confere os Elements nos espaços filhos.
scenarios/new-keeper.json
  "ledger": [{ "function": "guard", "currentValue": 0, "expected": 3 }]
  1. Linha 18 Chama a função de proteção com o valor atual 0 e espera 3.

O que precisa ser coberto

  • Todo constructor, ação e função de ledger precisa de um cenário.
  • Toda ação precisa de pelo menos um passo. Adicione um passo para cada ramo que você quer provar, como um que escreve e um que não escreve nada.
  • Uma ação que adiciona a uma lista precisa de um passo aceito e de um passo com expectedRefusal, qualquer que seja a sua oferta. O passo recusado prova que a oferta pode dizer não. Uma ação que só remove de uma lista precisa de um passo aceito.
  • Os valores esperados devem ser iguais ao que o constructor realmente retorna, com as funções de ledger já aplicadas.

Os passos recebem o nome do seu cenário. Uma mensagem como heal-after-damage-2 quer dizer o terceiro passo de heal-after-damage, porque o número conta a partir de 0. Outras mensagens contam os passos a partir de 1.

Um passo que diz esperar uma recusa de uma ação que não foi recusada falha, e o contrário também:

the step expects it to be refused with NOT_OFFERED
Add expectedRefusal

Uma ação sem nenhum passo falha com:

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

Uma ação de lista sem um passo aceito ou sem um passo recusado falha com:

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.

Valores esperados diferentes dos que o constructor retorna falham com:

Constructor output does not match its scenario.

Recusas

Uma ação de lista pode ser recusada. Um passo que espera isso nomeia o código em expectedRefusal e não lista escritas.

CódigoQuando
NOT_OFFEREDA entrada escolhida não está entre as entradas que a oferta permite.
ALREADY_IN_LISTA lista já tem a entrada.
LIST_FULLA lista está no tamanho máximo.
NOT_IN_LISTlist.remove nomeia uma entrada que a lista não tem.
LIST_CAPUm limite que a lista declara seria ultrapassado.
SAME_NAMEA lista já tem uma entrada com esse nome.

Este projeto prova várias delas. Ele também tem um passo em que uma proteção para a ação, então o passo espera nenhuma escrita e nenhuma recusa.

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. Linhas 7-12 Aceito: list.add escreve a corda.
  2. Linhas 13-19 Recusado: a lista já tem a corda.
  3. Linhas 20-26 Recusado: a oferta não permite a bigorna.
  4. Linhas 35-40 A mochila já tem duas entradas, então a proteção não escreve nada e nenhuma recusa é esperada.
  5. Linhas 41-48 Removido: a corda sai da lista.
  6. Linhas 49-55 Recusado: a corda não está mais na lista.
  7. Linha 57 A mochila termina só com a vela.

Executando

Verificar e visualizar no The Forge compila o projeto e executa todos os cenários. Nada é publicado e nenhum personagem ao vivo muda.

Próximo