How to test an private function that is in the middle of a bigger function?

Hello

I have something like:

defmodule Dog do
  def guard_house(woof) do
    case woof do
      "woof" -> bark(1)
      "woof woof" -> bark(2)
      "woof woof woof" -> bark(3)
      _ -> bark(0)
    end
    
    {:ok, "success"}
    
  end
  
  defp bark(times) do
    for i <- 0..times, do: outside_api("woof")
  end
end

Is there a way to check the attributes that bark is receiving?
I don’t want to make it public just for the test to pass
The output is a call to external api, so I don’t have how to check the result of it…

Thanks

It’s a bit hard to make specific recommendations given the psuedo code here, because I can’t tell what parts of its structure are just part of the example and what parts mirror your actual code.

In short though, to make your code testable you need to either emit a side effect you can measure, or you need to return a value. This may require changes to how the code is structured.

2 Likes

If I understand correctly, you’re actually trying to test the case, not the bark function. You could split up the logic like this:

defmodule Dog do
  def guard_house(woof) do
    woof
    |> number_of_barks()
    |> bark()

    {:ok, "success"}
  end

  def number_of_barks(woof) do
    case woof do
      # ...
    end
  end
end

Now you can test the case expression inside its own function and the code with the side effects is now completely trivial.

EDIT: And the case is actually a bit nicer now as well, since it doesn’t have the call to bark duplicated in every branch, it just returns a number.

One way to test the behavior is to mock the external API using a mocking library and verify that your module is calling the API with the right parameters.

You can test it using patch: Patch — patch v0.12.0

1 Like

TestServer is also a good option here: TestServer — TestServer v0.1.0

1 Like

My strong recommendation is not to test private functions or make them public only to test them. It is actually possible to over test. Add tests for the happy path of your public function, sure, and maybe some edge cases if they are critical, or complicated enough that tests will help give you confidence they have been implemented correctly (certainly write a test rather than test things manually). Whether or not a function is private should be between you and your public function, no one else should know, including the tests. Don’t end up having to rewrite tests just because you refactored the internal implementation of a function without changing its spec.

4 Likes