テストランナーの役割はただ1つ、解答を受け取り、すべてのテストを実行し、標準化された出力を返すことです。 Exercismのウェブサイトとのやり取りはすべて自動で行われるため、この仕様には含まれません。
two-fer)。/tmpを使うのがよいでしょう。results.jsonファイルを書き出さなければなりません。テストランナーには、解答1つあたり20秒間、CPU100%とメモリ3GBが割り当てられます。 20秒を過ぎると、プロセスは停止され、タイムアウトとして報告されます。
タイムアウトの可能性を減らすために、パフォーマンスのベストプラクティスに従うことを強くおすすめします。
results.jsonファイルでは、以下のフィールドを使用できます。
key:
version、type:number、presence: 必須
version: 1, 2, 3
このファイルが準拠する仕様のバージョンです。
1:テストランナーが個々のテストの情報を提供できないトラック向けです。2:テストランナーが個々のテストの情報を出力できるトラック向けです。コンセプト演習があるトラックでは、これが最低限必要なバージョンです。3:テストランナーが個々のテストをタスクに紐付けられるトラック向けです。key:
status、type:string、presence: 必須
version: 1, 2, 3
全体ステータスとして有効なのは、次のとおりです。
pass:すべてのテストが通りましたfail:少なくとも1つのテストのステータスがfailまたはerrorですerror:テストが1つも実行されませんでした(多くの場合、コンパイルエラーか構文エラーを意味します)errorステータスは、すべてのテストがエラーになった場合に_のみ_使ってください。
コンパイル言語では、通常これはコードがコンパイルできなかった結果です。
インタプリター言語では、これは実行時エラーです。たとえば、ファイルの解析を止めてしまう構文エラーなどです。
key:
message、type:string、presence:status=errorの場合、またはstatus=failかつversion=1の場合は必須
version: 1, 2, 3
ステータスがerror(テストが1つも正しく実行されなかった)の場合、トップレベルのmessageキーを指定してください。ここには、発生したエラーをユーザーに伝える内容を書きます。ユーザーが問題をデバッグするために受け取る唯一の情報なので、できるだけ明確に書かなければなりません。
/full/path/toのような形式ではなく、<solution-dir>/relative/pathのように簡略化してください。/full/path/toには、役に立たないECR固有の情報が含まれてしまうからですRubyの場合、構文エラーのときは、実行時エラーとスタックトレースを提供します。コンパイル言語では、コンパイルエラーを提供してください。
トップレベルのmessageの値は、65535文字に制限されています。
マルチバイト文字が含まれる場合、実際の最大長はそれより短くなります。
ステータスがerrorでない場合は、値をnullにするか、キー自体を省略してください。
key:
tests、type:array、presence:status=failまたはstatus=passの場合は必須
version: 2, 3
これはテスト結果の配列で、後述の「テストごと」セクションで説明します。
テストは、テストファイルに指定された順序で返さなければなりません。 テストをランダムな順序で実行する言語では、テストファイルに指定された順序に合わせて結果を並べ替える必要があるかもしれません。
その理由は、学習者には最初の失敗だけが表示されるため、正しい失敗が表示されることが重要だからです。テストは通常、テストファイル内でTDDの流れに沿って並んでおり、プラクティス演習では学習者がエディターでテストファイルを見ることができるため、結果をテストファイルと一致させることが重要です。
key:
name、type:string、presence: 必須
version: 2, 3
これは、人間が読める形式でのテストの名前です。
key:
test_code、type:string、presence: 演習がコンセプト演習の場合は必須
version: 2, 3
これは、コンセプト演習では必ず含めなければなりません。プラクティス演習では含めるべきです。
この要件の違いは、コンセプト演習では学習者にテストが表示されないため、test_codeが表示されないと演習を解くのが難しくなる一方、プラクティス演習ではテストが表示されることに由来します。
これは、テスト対象となるコマンドの本体です。たとえば、次のRubyのテストは、
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
次のようなtest_codeの値を返すべきです。
"cart = ShoppingCart.new
cart.add(:STARIC)
cart.add(:MEDNEW)
cart.add(:MEDNEW)
assert_equal 'Newspaper, Rice', cart.items_list"
(JSONとして有効にするため、改行は\nに置き換えます)。
key:
status、type:string、presence: 必須
version: 2, 3
テストごとのステータスとして有効なのは、次のとおりです。
pass:テストが通りましたfail:テストが失敗しましたerror:テストがエラーになりました。つまり、値が返されませんでしたkey:
message、type:string、presence:statusがfailまたはerrorの場合は必須
version: 2, 3
テストごとのmessageキーは、statusがfailまたはerrorのテストの結果を返すために使います。できるだけ人間が読みやすい形にしてください。ここに書いた内容は、学習者のテストが通らなかったときに表示されます。テストの失敗メッセージやエラーメッセージがない場合は、値をnullにするか、キー自体を省略してください。ここにテストスイートの出力を書いてもかまいません。messageの値には長さの制限がありません。
key:
output、type:string、presence: 任意
version: 2, 3
テストごとのoutputキーは、ユーザーがテストのために意図的に出力したものを保存して表示するために使います。
puts、Pythonのprint、C#のDebug.WriteLine)、ユーザーが使えるメソッドを用意してもかまいません(例:Rubyのテストランナーは、標準のputsメソッドと同じ特性を持つ、グローバルに使えるdebugメソッドをユーザーに提供しています)。key:
task_id、type:number、presence: 任意
version: 3
テストを、タスクのIDを介して特定のタスクに紐付けます。このIDは、タスクの見出しの先頭で使われている番号です。テストは、正確に_1つ_のタスクに紐付けられる場合にのみ、タスクにリンクしてください。
現時点では、テストを紐付けられる明確なタスクがあるのはコンセプト演習だけですが、今後変わるかもしれません。
たとえば、次のinstructions.mdファイルを考えてみましょう。
# 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
...
この指示では、2つのタスクが定義されています。
その場合、results.jsonファイルには次のようなエントリを書けます。
{
"name": "Expected oven time in minutes",
"status": "pass",
"task_id": 1,
"test_code": "Assert.Equal(40, Lasagna.ExpectedMinutesInOven());"
}
これで、このテストは最初のタスク「オーブンの所要時間を分単位で定義する」に紐付きました。nameがタスクの説明と一致している必要は_ありません_。
トラックでこれを実装する方法はいくつかあります。
.meta/config.jsonファイルなど)に保存し、この情報を生成されたresults.jsonファイルにマージする。以下は、バージョンごとに有効なresults.jsonファイルがどんな形になるかの例です。
{
"version": 1,
"status": "fail",
"message": "Failed: test_answer\nExpected: 42, actual: 3"
}
{
"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()"
}
]
}
{
"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
}
]
}
学習者の解答がテストに失敗したときは、次のような表示になるべきです。
Test Code:
<test_code>
Test Result:
<message>
解答がテストに通ったときは、次のような表示になるべきです。
Test Code:
<test_code>
やり方は1つではなく、決まったパターンがあるわけでもありません。 これまでに採られてきた方法はいくつかあります。