테스트 러너는 풀이를 받아 모든 테스트를 실행하고 표준화된 출력을 반환하는 한 가지 역할만 담당해요. Exercism 웹사이트와의 모든 상호작용은 자동으로 처리되며, 이 명세의 범위에 포함되지 않아요.
two-fer)./tmp를 사용하는 게 좋아요.results.json 파일을 써야 해요.테스트 러너는 풀이 하나당 20초 동안 CPU 100%와 3GB 메모리를 사용할 수 있어요. 20초가 지나면 프로세스가 중단되고 시간 초과로 보고돼요.
시간 초과 가능성을 줄이려면 성능 모범 사례 문서를 따르는 것을 적극 권장해요.
results.json 파일에서는 다음 필드를 지원해요.
키:
version, 타입:number, 포함 여부: 필수
버전: 1, 2, 3
이 파일이 따르는 명세의 버전이에요.
1: 테스트 러너가 개별 테스트에 대한 정보를 제공할 수 없는 트랙용이에요.2: 테스트 러너가 개별 테스트 정보를 출력할 수 있는 트랙용이에요. 개념 연습 문제가 있는 트랙의 최소 필수 버전이에요.3: 테스트 러너가 개별 테스트를 작업에 연결할 수 있는 트랙용이에요.키:
status, 타입:string, 포함 여부: 필수
버전: 1, 2, 3
다음 전체 상태가 유효해요.
pass: 모든 테스트가 통과했어요fail: 하나 이상의 테스트가 fail 또는 error 상태예요error: 실행된 테스트가 없어요 (보통 컴파일 오류나 구문 오류를 뜻해요)error 상태는 오직 모든 테스트에서 오류가 발생한 경우에만 사용해야 해요. 컴파일 언어에서는 보통 코드가 컴파일되지 않아 생기는 결과예요. 인터프리터 언어에서는 파일 파싱을 막는 구문 오류 같은 런타임 오류예요.
키:
message, 타입:string, 포함 여부:status=error일 때, 또는status=fail이고version=1일 때 필수
버전: 1, 2, 3
상태가 error일 때(테스트가 하나도 제대로 실행되지 않았을 때)는 최상위 message 키를 제공해야 해요. 이 키는 사용자에게 발생한 오류를 알려줘야 해요. 문제를 디버깅하는 방법에 대해 사용자가 받는 유일한 정보이므로, 최대한 명확해야 해요.
/full/path/to 형태는 도움이 되지 않는 ECR 관련 데이터를 포함하게 되므로, 경로를 <solution-dir>/relative/path처럼 단순화하세요.Ruby에서는 구문 오류가 발생하면 런타임 오류와 스택 트레이스를 제공해요. 컴파일 언어에서는 컴파일 오류를 제공해야 해요.
최상위 message 값은 65535자로 제한돼요. 값에 멀티바이트 문자가 포함되면 실제 최대 길이는 그보다 짧아져요.
상태가 error가 아니면 값을 null로 설정하거나 키를 아예 생략하세요.
키:
tests, 타입:array, 포함 여부:status=fail또는status=pass일 때 필수
버전: 2, 3
아래 "테스트별" 섹션에 명시된 대로, 테스트 결과의 배열이에요.
테스트는 테스트 파일에 명시된 순서대로 반드시 반환해야 해요. 테스트를 무작위 순서로 실행하는 언어라면, 결과를 테스트 파일에 명시된 순서에 맞춰 다시 정렬해야 할 수도 있어요.
그 이유는 학생에게는 첫 번째 실패만 보여주기 때문에, 올바른 실패가 표시되는 게 중요하기 때문이에요. 테스트는 보통 테스트 파일에 TDD 방식으로 정렬되어 있고, 실습 연습 문제에서는 학생이 편집기에서 테스트 파일을 보기 때문에, 결과를 테스트 파일과 일치시키는 게 아주 중요해요.
키:
name, 타입:string, 포함 여부: 필수
버전: 2, 3
사람이 읽기 쉬운 형식의 테스트 이름이에요.
키:
test_code, 타입:string, 포함 여부: 개념 연습 문제일 때 필수
버전: 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로 바꿔요).
키:
status, 타입:string, 포함 여부: 필수
버전: 2, 3
다음 테스트별 상태가 유효해요.
pass: 테스트가 통과했어요fail: 테스트가 실패했어요error: 테스트에서 오류가 발생했어요. 즉, 값을 반환하지 않았어요키:
message, 타입:string, 포함 여부:status가fail또는error일 때 필수
버전: 2, 3
테스트별 message 키는 status가 fail 또는 error인 테스트의 결과를 반환할 때 사용해요. 최대한 사람이 읽기 쉬워야 해요. 여기에 쓰인 내용은 학생의 테스트가 통과하지 못했을 때 학생에게 표시돼요. 테스트 실패 메시지나 오류 메시지가 없으면 값을 null로 설정하거나 키를 아예 생략하세요. 여기에 테스트 스위트의 출력을 내보내도 괜찮아요. message 값은 길이 제한이 없어요.
키:
output, 타입:string, 포함 여부: 선택
버전: 2, 3
테스트별 output 키는 사용자가 테스트를 위해 의도적으로 출력한 내용을 저장하고 내보낼 때 사용해야 해요.
puts, Python의 print, C#의 Debug.WriteLine), 사용자가 쓸 수 있는 메서드를 제공할 수도 있어요(예를 들어 Ruby 테스트 러너는 표준 puts 메서드와 같은 특성을 지닌, 전역에서 사용할 수 있는 debug 메서드를 사용자에게 제공해요).키:
task_id, 타입:number, 포함 여부: 선택
버전: 3
테스트를 작업 ID를 통해 특정 작업에 연결해요. 작업 ID는 작업 제목 앞에 쓰인 숫자예요. 정확히 _하나_의 작업에만 연결할 수 있을 때만 테스트를 작업에 연결하세요.
현재로선 개념 연습 문제에만 테스트를 연결할 수 있는 잘 정의된 작업이 있지만, 나중에는 달라질 수도 있어요.
예를 들어 다음 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
...
이 지시문은 두 개의 작업을 정의해요.
그러면 results.json 파일에 다음과 같은 항목을 넣을 수 있어요.
{
"name": "Expected oven time in minutes",
"status": "pass",
"task_id": 1,
"test_code": "Assert.Equal(40, Lasagna.ExpectedMinutesInOven());"
}
이 테스트는 이제 첫 번째 작업인 "예상 오븐 시간을 분 단위로 정의하기"에 연결돼요. 이름이 작업 설명과 꼭 일치해야 하는 건 아니라는 점에 유의하세요.
트랙에서 이를 구현하는 방법은 여러 가지예요.
.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>
모든 길은 로마로 통한다고, 여기에 정해진 방법은 없어요. 지금까지는 여러 가지 접근 방식이 쓰였어요.