NoDisplayName
NoDisplayName

Reputation: 15736

How to test a function call from a different module

There are probably lots of similar questions here but I still don't understand how it's done.

Let's say I have the following trivial module:

defmodule ModuleOne do

  def do_something(argument) do
    argument
    |> do_first_thing()
    |> do_second_thing()
    |> ModuleTwo.do_something()
  end

end

Now, I have ModuleTwo covered with tests so it doesn't make sense to duplicate that testing logic. Also it's not Twitter API module or something of the kind so I dont think it's a good idea to come up with a compile-time mock module ( as far as I can see, it's a good idea in case cases, like HTTP calls but doing that for every external module call will obviously turn into a mess ) and also I don't want to pass a function as an argument just for the sake of testing ( especially if I have calls to multiple external modules ) because it messes up the interface with unnecessary things.

Also people suggest not to use mocks, like the meck library, which is the most obvious decision here, but I don't understand why ...

Anyway, what would be a good way to test this module considering all the suggestions above?

Thank you

Upvotes: 1

Views: 131

Answers (2)

ryanwinchester
ryanwinchester

Reputation: 12127

I agree with Lukáš Doležal. Don't call ModuleTwo.do_something() in ModuleOne.do_something(). The ideal is to have small functions that perform one task well. So, ideally you would do ModuleOne.do_something() |> ModuleTwo.do_something() instead.

However, sometimes the things that are ideal are not practical. Without context here we won't know. If that is the case, and you really want to cover everything with zero duplication, then there is a compromise that might work for you:

Instead of:

defmodule ModuleOne do

  def foo(bar) do
    bar
    |> first()
    |> second()
    |> ModuleTwo.foo()
  end

end

Do:

defmodule ModuleOne do

  def foo(bar), do: do_foo(bar) |> ModuleTwo.foo()

  def do_foo(bar) do
    bar
    |> first()
    |> second()
  end

end

And then just test ModuleOne.do_foo/1 instead of ModuleOne.foo/1

Upvotes: 0

Lukáš Doležal
Lukáš Doležal

Reputation: 289

My suggestions would be:

1) Don't call the ModuleTwo in ModuleOne at all. Then test only the transformation before. And move the ModuleTwo call to the caller code or other "integration" module. Then test the caller code/integration model separately on integration level.

2) Use meck to test that ModuleTwo has been called with the argument you expect. But it is then similar to 1) as it practically test the 2 transformation steps.

Upvotes: 1

Related Questions