web-dev-qa-db-ja.com

ElixirのExUnitのモジュールでプライベート関数をテストする方法はありますか?

defpで定義された関数はエクスポートされないため、モジュール以外の場所では実行できません。

55
Noah Blues

いいえ、ExUnit経由でテストする方法はありません。

私は個人的にプライベート関数のテストを避けています。通常、動作の代わりに実装をテストし、コードを変更する必要があるとすぐにそれらのテストが失敗するためです。代わりに、パブリック関数を介して予想される動作をテストし、小さくて一貫したチャンクに分割します。

84
José Valim

モジュール定義では、@compileディレクティブ-プライベート関数をエクスポートするonlyテスト環境で。

defmodule Foo do
  @compile if Mix.env == :test, do: :export_all

  # This will be exported for tests
  defp bar() do
  ... code ...
  end
end
12
Michael Bishop

マクロを使用して、環境に応じて関数の可視性を変更できます。

defmacro defp_testable(head, body \\ nil) do
  if Mix.env == :test do
    quote do
      def unquote(head) do
        unquote(body[:do])
      end
    end
  else
    quote do
      defp unquote(head) do
        unquote(body[:do])
      end
    end
  end
end

次に、次のように関数をテストに公開できます。

defp_testable myfunc do
  ...
end

ホセの回答にある理由から、これは控えめに使用することをお勧めします。モジュールの外部動作をテストする代わりにはなりません。ただし、特定のシナリオでは価値があります。

ソース

6
acj

ExUnitを使用したテストのコンテキストであっても、プライベート関数をモジュールの外部から呼び出すことはできません。

テスト用にプライベート関数を公開するための複雑な方法を提案する人もいるので、もっと簡単に見える次の2つを提案します。

1)テストする関数を公開しますが、@doc falseでマークします。つまり、モジュールの公開APIの一部ではありません。

2)あるいは、テストする関数がdefp fooの場合、同じモジュールでdef test_fooを作成します。これは、テスト中に変更する引数を受け取り、それらをfooは期待し、最後にfooを呼び出します。このようなテスト中にのみ、特別なテスト関数を生成することもできます

  if Mix.env == :test do
    def test_foo ...
  end

これらの代替案はいずれも単純で、プロジェクトに追加の依存関係は必要ありません。

もちろん、他の人が述べたように、一般的なルールはプライベート関数のテストを避けることですが、それらをテストすることは、テストを容易にし、テストの範囲を広げる方法です。

良いコーディング!

0
mljrg