Mox

Functional mocking microlibrary

ElixirConf EU 2018, by @hubertlepicki

@hubertlepicki

ElixirConf EU 2018, by @hubertlepicki

https://slides.com/

hubertlepicki

ElixirConf EU 2018, by @hubertlepicki

Mox

github.com/plataformatec/mox

ElixirConf EU 2018, by @hubertlepicki

Mox is a functional mocking microlibrary based on the idea of smart explicit contracts and Ethereum

ElixirConf EU 2018, by @hubertlepicki

by José Valim, Plataformatec blog, 2015

ElixirConf EU 2018, by @hubertlepicki

Feature missing: help needed

ElixirConf EU 2018, by @hubertlepicki

Hubert, José's Minion

ElixirConf EU 2018, by @hubertlepicki

Mox principles

  • No ad-hoc mocks. You can only create mocks based on behaviours

  • No dynamic generation of modules during tests. Mocks are preferably defined in your test_helper.exs or in a setup_all block and not per test (I disagree!)

  • Concurrency support. Tests using the same mock can still use async: true

  • Rely on pattern matching and function clauses for asserting on the input instead of complex expectation rules

ElixirConf EU 2018, by @hubertlepicki

Define behaviour & code

Declare mock

ElixirConf EU 2018, by @hubertlepicki

defmodule CalcBehaviour do
  @callback multiply(integer(), integer()) :: integer()
end

defmodule Calc do
  @behaviour CalcBehaviour
  def multiply(a, b), do: a * b end
end
test/support/mocks.ex

defmock CalcMock, for: CalcBehaviour

config.exs

test.exs

ElixirConf EU 2018, by @hubertlepicki

Application.put_env(
  :my_app,
  :calc,
  Calc
)
Application.put_env(
  :my_app,
  :calc,
  CalcMock
)

In your config/...

In your app code...

ElixirConf EU 2018, by @hubertlepicki

defmodule Rectangle do
  @calc Application.get_env(:my_app, :calc)

  def area(width, height) do
    @calc.multiply(width, height)
  end
end


In your tests code...

ElixirConf EU 2018, by @hubertlepicki

setup :verify_on_exit!

test "computes area with current math rules" do
  
  CalcMock
  |> expect(:multiply, fn 2, y -> 2 + y end)

  
  assert Rectangle.area(2, 3) == 5
end

In your tests code...

ElixirConf EU 2018, by @hubertlepicki

setup :verify_on_exit!

test "computes area with current math rules" do
  
  CalcMock
  |> stub(:multiply, fn 2, y -> 2 + y end)

  
  assert Rectangle.area(2, 3) == 5
end

Other goodies

  • set_mox_private/1
  • set_mox_global/1
  • set_mox_from_context/1
  • allow/3
  • verify_on_exit/1
  • verify!

Code: Done

Try mox!

Thanks!

Mox

By Hubert Łępicki

Mox

  • 1,229