[Elixir]ExUnitで同名のtestが存在した時にコンパイルエラーにする

1行まとめ

  • ExUnitにおけるテストケースの重複時にコンパイルエラーにしたい場合、 test_helper.exsCode.compiler_options(warnings_as_errors: true) オプションを追加しておこう
    • 多分、これはチーム開発では大いに役立ちます

ExUnitが test マクロを関数定義するまで

以下のようなテストケースがあったとします。

defmodule ErrorSampleExunitTest do
  use ExUnit.Case

  test "the truth" do
    assert 1 + 1 == 2
  end
end

この時、 test マクロで定義されたところは __ErrorSampleExunitTest__.':test the truth' としてコンパイル時に定義されます。

Elixir1.2.1では以下の行での話になります。

...
    quote bind_quoted: binding do
      test = :"test #{message}"
      ExUnit.Case.__on_definition__(__ENV__, test)
      def unquote(test)(unquote(var)), do: unquote(contents)
    end
...

同名の test が存在した場合

さて、この時に複数の同名のテストが存在した場合はどうでしょう?

例えば以下。

defmodule ErrorSampleExunitTest do
  use ExUnit.Case

  test "the truth" do
    assert 1 + 1 == 2
  end

  test "the truth" do
    assert 1 + 2 == 3
  end
end

この場合、コンパイル時にCLIで以下のような warn が表示されます。

test/error_sample_exunit_test.exs:8: warning: this clause cannot match because a previous clause at line 4 always matches

テストケースを記述するコードは、 .exs の拡張子を持つので、このようなwarnはテスト実行毎に表示されます。なので、実行を注意深く見ていると、このエラーを知ることができます。

ただ、他のテスト自体は実行されます。

コンパイルエラーにする

ただ、warnではなくコンパイルエラーにしたほうが親切なのでは?と思い、手元でコンパイルエラーになるようにExUnitを直接修正してみました。

ExUnitのtestマクロでは、以下の2点でコンパイル時に関数を定義します。

なので、その直前で以下のように既存モジュールに定義済みの同名関数があるかどうかを検出させ、trueであればraiseするようにします。

if Module.defines?(__MODULE__, {test, 1}), do: raise("'#{test}' in #{__MODULE__} is already defined")

コンパイラオプションで回避する

ただ、これはコンパイルオプションだけで回避することができるみたいです。PR投げてみようと思った矢先、issueを見つけました。

これによると、 test_helper.exsに以下を追加することで、コンパイルを失敗させることができるそうです。

Code.compiler_options(warnings_as_errors: true)

確かにコンパイルエラーに。

$ mix test
Compiled lib/error_sample_exunit.ex
test/error_sample_exunit_test.exs:8: warning: this clause cannot match because a previous clause at line 4 always matches
Compilation failed due to warnings while using the --warnings-as-errors option

小さなライブラリは別に良いのですが、チーム開発をしている時なんかはこのオプションは必要そうですね。

でも、このwarnは少し丁寧ではない気も…とはいえ、warnで止めていること自体は正しいと思いますし、ここは学びを得た、で止めておこうと思います。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中