Best practices for testing with doctest

My recommendation, especially if you have a lot of these methods is to separate out your side-effects from your business logic in a similar way that any/most of the functions that you create with Ecto actually create/operate on a Changeset rather than manipulating the database directly (Plug operates similarly). So your guess/2 function instead of looking something like this:

def guess(number, range) do
  IO.puts "Is it 500?\nIs it 250?\nIs it 375?\nIs it 312?\nIs it 281?\nIs it 265?\nIs it 273?\n273\n"
end

Would look more like this:

def guess(number, range) do
  %{
    output: "Is it 500?\nIs it 250?\nIs it 375?\nIs it 312?\nIs it 281?\nIs it 265?\nIs it 273?\n273\n"
  }
end

Which you could then test like:

test "Basic game output" do
  assert guess(273, 1..1000) ==
    %{output: "Is it 500?\nIs it 250?\nIs it 375?\nIs it 312?\nIs it 281?\nIs it 265?\nIs it 273?\n273\n"}
end

This will make a doctest easier to write.

Of course you do need to put your side-effects somewhere so you can have a simple function such as:

def send_output_to_terminal(%{output: output}) do
  IO.puts(output)
end

And the send_output_to_terminal function is of course very easy to test. One benefit of this decoupling is that if you now want to create a new interface to your application (for example over a Phoenix Socket) you can keep all your business logic the same, and just write a send_output_to_socket function.

To provide better structure rather than operating one a map you can create a simple Struct to represent the results of your business/game logic. You can also add a key to represent if you should run System.halt/1 or not.

I recommend this article all the time, but in case you haven’t seen it I’d highly recommend this article: http://theerlangelist.com/article/spawn_or_not

While it is primarily about processes, it contains a good example of this type of decoupling of side-effects from business logic.

If you have the time and resources, PragDave’s course is also excellent: Elixir for Programmers (PragDave) (Currently on offer for $30!)

3 Likes