Exercism에서 Elixir 연습 문제를 테스트하는 방법을 배워요
터미널에서 연습 문제의 기본 디렉터리로 이동한 다음, 아래 명령으로 테스트를 실행해요:
$ mix test
이 명령은 test 하위 폴더에 있는 테스트 파일, 즉 이름이 _test.exs로 끝나는 파일을 실행해요.
연습 문제의 테스트 스위트에서는 첫 번째 테스트를 빼고 모두 건너뛰도록 태그되어 있어요.
테스트 하나를 통과시키면, 다음 테스트의 @tag :pending을 # 기호로 주석 처리해서 건너뛰기를 해제할 수 있어요.
예를 들어:
# @tag :pending
test "shouting" do
assert Bob.hey("WATCH OUT!") == "Whoa, chill out!"
end
모든 테스트를 한 번에 실행하고 싶다면, mix test 명령에 --include 플래그를 사용해서 건너뛴 테스트를 모두 포함할 수 있어요:
$ mix test --include pending
또는 테스트 스위트에서 ExUnit.configure 줄을 주석 처리해서 모든 테스트를 활성화할 수 있어요.
# ExUnit.configure exclude: :pending, trace: true
ExUnit과 mix test는 테스트를 그룹으로 묶고, 태그를 달고, 실행하는 여러 가지 방법과 테스트 실행을 제어하는 다양한 방법을 제공해요. 그중 상당수를 아래에 정리했어요.
문서:
파일을 지정하면 mix test로 한 파일에 있는 모든 테스트를 실행할 수 있어요:
$ mix test test/<FILE>.exs
참고: 이 방법을 사용할 때
tagging에 따라 실제로 실행되는 테스트가 달라질 수 있어요.
파일에서 테스트의 줄 번호를 지정하면 개별 테스트를 실행할 수 있어요:
$ mix test test/<FILE>.exs:LINENUM
:로 구분한 여러 줄 번호를 지정하면 여러 테스트를 실행할 수 있어요.
예를 들어, 줄 번호와 함께 다음 내용이 담긴 파일이 있다고 해봐요:
test "Test 1" do # 1
# test implementation # 2-6
end # 7
# 8
test "Test 2" do # 9
# test implementation # 10-21
end # 22
# 23
test "Test 3" do # 24
# test implementation # 25-35
end # 36
1번째와 3번째 테스트는 이렇게 실행할 수 있어요:
$ mix test test/FILE.exs:1:24
참고: 줄 번호로 테스트를 지정할 때는
tagging이 무시돼요.
describe를 사용하면 테스트를 그룹으로 묶을 수 있어요:
describe "short test group description" do
test "test description" do
# test implementation
end
test "another test description" do
# test implementation
end
end
그룹에 있는 모든 테스트도 개별 테스트를 지정해서 실행할 때처럼 파일에서 그룹의 줄 번호를 지정하면 실행할 수 있어요.
문서:
mix test 옵션--include와 --exclude - @tag를 기준으로 특정 테스트를 실행하거나 실행하지 않아요--failed - 마지막으로 실행했을 때 실패한 테스트만 실행해요--max-failures - 테스트 실패가 이 개수에 도달하면 스위트가 테스트 실행을 중단해요--seed - 테스트 순서를 무작위로 정하는 데 사용하는 난수 생성기의 시드를 지정해요. --seed 0은 무작위화를 비활성화해서 한 파일의 테스트가 항상 정의된 순서대로 실행되게 해요--stale - --stale로 마지막으로 테스트를 실행한 이후 변경된 모듈을 참조하는 테스트만 실행해요--only task_id:1 - 또는 다른 번호를 붙여서, 학습 문제에서는 특정 과제와 연결된 테스트만 실행해요문서:
Elixir 연습 문제에는 lib 하위 디렉터리에 뼈대 구현 파일이 들어 있어요. 이 파일에는 구현해야 할 모듈과 함수의 윤곽이 잡혀 있어요. 대부분의 연습 문제에서는 함수 선언 위에 타입 명세가 있어요. 타입 명세는 @spec 태그로 시작하고, 보통 @spec function_name(type1, type2) :: return_type 형식을 따라요. 이것들은 Elixir와 Erlang에서 문서 역할을 하고, Dialyzer라는 도구와 함께 타입 불일치와 잠재적인 버그를 찾는 데 사용돼요. 더 자세한 내용은 타입 명세 문서를 참고해요. Dialyzer에 대한 문서는 Erlang -- dialyzer를 봐요.
원한다면 Dialyzer로 구현의 타입을 검사해 볼 수도 있어요. 그러려면 몇 가지 단계를 거쳐야 해요. 먼저 연습 문제의 mix.exs 파일에 Dialyxir 의존성을 추가해야 해요.
defp deps do
# Add this:
[{:dialyxir, "~> 0.4", only: [:dev]}]
end
그런 다음 명령줄에서 mix 태스크를 사용해 내려받고 컴파일해요:
$ mix deps.get
...
$ mix deps.compile
...
Dialyzer를 처음 실행하는 거라면 아마 plt 파일이 없을 거예요. 영구 조회 테이블(persistent lookup table), 즉 PLT는 Elixir와 Erlang에 내장된 타입 정보를 캐시하는 데 사용돼요. 적절한 기본값으로 plt를 만들려면 다음을 실행해요:
$ mix dialyzer --plt
마지막으로, 이렇게 실행할 수 있어요:
$ mix dialyzer
경로를 자신의 시스템에 있는 Elixir 라이브러리 경로로 바꿔야 해요. 예를 들어 homebrew로 Elixir를 설치했다면 보통 /usr/local/Cellar/elixir/1.3.2 아래에서 찾을 수 있어요.
다시 말하지만, Dialyzer를 실행하고 모든 경고를 없애는 것은 연습 문제를 풀 때 선택 사항이에요. Dialyzer 경고는 해석하기 어려울 수 있어요. 예를 들어, 아주 엉뚱한 Bob 연습 문제 구현에 대한 경고를 살펴봐요.
defmodule Bob do
@spec hey(input :: String.t()) :: String.t()
def hey(input) do
1
end
def hey(input) do
end
end
이 코드는 다음과 같은 경고를 만들어요.
bob.exs:2: Invalid type specification for function 'Elixir.Bob':hey/1. The success typing is (_) -> 1
bob.exs:7: The variable _input@1 can never match since previous clauses completely covered the type any()
첫 번째 경고는 함수가 올바른 타입을 반환하지 않는다는 뜻이에요. 마지막 경고는 첫 번째 함수 정의가 항상 일치하기 때문에 두 번째 함수 정의에 절대 도달할 수 없다는 뜻이에요.