kovpack
kovpack

Reputation: 5045

Test method delegation in Elixir

I've got two modules:

defmodule Base.ModuleOne do
  def do_stuff(opts) do
    "some stuff with opts"
  end
end

defmodule Base.ModuleTwo do
  defdelegate do_stuff(opts), to: Base.ModuleOne
end

What is the proper way of testing delegation without copy-pasting tests for Base.ModuleOne.do_stuff/1 function under different namespace?

Upvotes: 4

Views: 520

Answers (1)

Paul Fioravanti
Paul Fioravanti

Reputation: 16793

As of the writing of this answer, I haven't found an "official" way to test defdelegate either. The only choices I can think of in your case are:

  1. Just ignore testing of Base.ModuleTwo.do_stuff(opts), assuming you have your bases covered in tests for Base.ModuleOne.do_stuff(opts).
  2. Move the bulk of (if not all of) the tests in Base.ModuleOne.do_stuff(opts) up to the tests for Base.ModuleTwo.do_stuff(opts) so your tests become directly concerned with the public interface of your module, relegating Base.ModuleOne to be "private" implementation detail.
  3. Since mocking would seem to be generally out of favour in Elixir, consider replacing defdelegate with dependency injection (using a function or module; see previous link for details), which would then allow you to write tests in the following kind of way:

Module:

defmodule Base.ModuleTwo do
  def do_stuff(opts, dependency \\ Base.ModuleOne)
    dependency.do_stuff(opts)
  end
end

Test:

defmodule ModuleTwoTest do
  use ExUnit.Case

  describe "Base.ModuleTwo.do_stuff/2" do
    defmodule TestDependency do
      def do_stuff(_opts) do
        send self(), :do_stuff
      end
    end

    test "calls do_stuff/1 on its dependency" do
      opts = %{foo: "bar"} # or whatever the `opts` should be
      Base.ModuleTwo.do_stuff(opts, TestDependency)
      assert_received :do_stuff
    end
  end
end

Upvotes: 2

Related Questions