Elixir 트랙에서 테스트하기

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

그 밖의 Elixir 테스트 기능

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 - 또는 다른 번호를 붙여서, 학습 문제에서는 특정 과제와 연결된 테스트만 실행해요

문서:

타입 명세와 Dialyzer (DIscrepancy AnalYZer for ERlang programs)

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()

첫 번째 경고는 함수가 올바른 타입을 반환하지 않는다는 뜻이에요. 마지막 경고는 첫 번째 함수 정의가 항상 일치하기 때문에 두 번째 함수 정의에 절대 도달할 수 없다는 뜻이에요.