Red Green Repeat Adventures of a Spec Driven Junkie

Mocking Elixir IO.puts

I’m diving head first into Elixir, but not following a linear approach. I’m taking the best experience I have from other programming languages and diving into parts of elixir I need. (So, I will be skipping lots of language details.)

Last post, I got into testing and building executables. The minimum for building out confident code for a client.

This time, let’s get into mocking. Not just any mocking, but mocking out user input and output! Software may interact with a person… and simulating a person through mocking will reduce development time.

Mocking in ExUnit

I love RSpec’s mocking faciities and with the great experience I had with ExUnit, I expected fantastic mocking.

At the time of writing, there wasn’t any mocking built-in to ExUnit. :-/ Shame, the relationship started so well!

I found this mock project by jjh42 and it’s fulfilling my mocking needs.

Mocking other functions is easy, but mocking input and output… even RSpec had a hard time with that! Let’s see how to mock out user input and output with elixir.


The main Elixir method to print to the console or to debug is using IO.puts. This is the equivalent of Ruby’s puts or Python’s print, C’s printf. Where would programming be without this fundmental feedback tool??

The README explains how to mock IO.puts:

defmodule MyTest do
  use ExUnit.Case, async: false
  import Mock

  test_with_mock "test_name", IO, [:passthrough], [] do
    IO.puts "hello"
    assert called IO.puts "hello"

Simple right?

Well, when I started to run tests, I started to see:

vagrant@vagrant:/vagrant/hello$ mix test
Compiling 1 file (.ex)

Finished in 0.2 seconds
3 tests, 0 failures

Randomized with seed 812063

Huh? I thought I was mocking out the function. Why is it printing to the screen?


Looks like the :passthrough option is like RSpec’s and_call_original, which is useful when wanting to use the original method in the test.

In this case though, not printing to console would be desirable. I love to have continuous green dots.

To elimiinate output, remove :passthrough as an option to mock:

  test_with_mock "test_name", IO, [], [] do
    IO.puts "hello"
    assert called IO.puts "hello"


vagrant@vagrant:/vagrant/hello$ mix test

  1) test test_name (HelloTest)
     ** (UndefinedFunctionError) function IO.puts/1 is undefined or private. Did you mean one of:

           * puts/1
           * puts/2

     code: IO.puts "hello"
       (elixir) IO.puts("hello")
       test/hello_test.exs:14: (test)


Finished in 0.2 seconds
3 tests, 1 failure

Randomized with seed 319412

Weird… so the :passthrough option was not causing the outpu. So, how I do mock out IO.puts without on screen output?

Mocking Functions

Looking at other examples on the README, there are functions associated like so:

 test "test_name" do
    with_mock HTTPotion, [get: fn(_url) -> "<html></html>" end] do
      # Tests that make the expected call
      assert called HTTPotion.get("")

Let’s try using a simple function to IO.puts:

  test_with_mock "test_name", IO, [], [puts: fn(_) -> nil end] do
    IO.puts "hello"
    assert called IO.puts "hello"

Running everything again:

vagrant@vagrant:/vagrant/hello$ mix test

Finished in 0.2 seconds
3 tests, 0 failures

Randomized with seed 356012

Nice, nothing extra on the output line. This took a little more work, but it makes sense.


This is a quick tour of mocking in elixir using jjh42’s mocking library. Getting IO.puts mocked out so there is no on-screen output during test runs.

This time, I covered IO.puts. Next time, I will go in-depth with IO.gets and also add some functionality.