TDD with Elixir
What to look for, to do TDD,
in a language you're not familiar with.
I'm new to Elixir
I'm a Software Crafter
We all do tests
at some point…
End user, in prod
Automated test, in dev
Not all code is easy to test
But TDD code is the easiest
Tests
Driven
Development
3 steps, iterative
How to
TDD
with Elixir?
My requirements
- How can I run tests?
- Can I have a watch mode?
- How can I mock things?
Bonuses
- Can I run a subset of tests easily?
- Are failing tests reports easy to read?
How can I run tests?
# test_helper.exs
ExUnit.start()
# my_super_module_test.exs
defmodule MySuperModuleTest do
use ExUnit.Case
test "add two numbers" do
result = MySuperModule.add 1, 2
assert result == 3
end
end
Standard convention
mix test
Can I have a watch mode?
🎁 Because TDD is awesome
# mix.exs (Elixir 1.4)
def deps do
[{:mix_test_watch, "~> 0.5", only: :dev, runtime: false}]
end
# mix.exs (Elixir 1.3 and earlier)
def deps do
[{:mix_test_watch, "~> 0.5", only: :dev}]
end
mix test.watch
How can I mock things?
Don't rush on mocks
Credits Stefano Alletti
Hexagonal Architecture
Elixir Behaviours
Abstract
Domain-API
Interface
Concrete
Infrastructure
Implementation
Inject a custom one to test
# Domain
module PoetryReader do
@poetry_library Application.get_env(:poetry_library)
def give_me_some_poetry do
@poetry_library.get_a_poem()
|> do_some_other_transformation
end
end
module PoetryLibrary do
@callback get_a_poem() :: {:ok, String.t()}
end
# Infrastructure
module PoetryLibrary.Http do
@behaviour MyApp.PoetryLibrary
def get_a_poem() do
url = "https://some-domain.com/poems/random"
headers = [{"Accept", "application/json"}]
HTTPoison.get!(url, headers)
|> Map.get(:body)
|> decode_response_into_string
end
end
# Application setup
config :poetry_library, PoetryLibrary.Http
Meet Mox
Mocks and explicit contracts in Elixir
def deps do
[{:mox, "~> 0.3", only: :test}]
end
# test/test_helper.ex
Mox.defmock(PoetryLibrary.Mock, for: PoetryLibrary)
Application.put_env(:poetry_library, PoetryLibrary.Mock)
# As a stub
PoetryLibrary.Mock
|> stub(:get_a_poem, fn() -> {:ok, "Some verses for you"} end)
# As a mock
PoetryLibrary.Mock
|> expect(:get_a_poem, fn() -> {:ok, "Some verses for you"} end)
Bonuses
mix test.watch --stale
Are failing tests reports readable?
ExDocs tests
📚 Ensure your docs examples are up-to-date
defmodule MySuperModule do
@doc """
Return a list of things.
## Examples
iex> MySuperModule.list()
[1, 4, true, 3]
"""
def list(), do: [1, 4, true, 3]
end
defmodule MySuperModuleTest do
use ExUnit.Case
doctest MySuperModule
# …
end
If you're going to write crappy code
in a new language…
Do TDD, so you can refactor later!
Going further
About me
@nicoespeon
Web developer at Busbud 🚎
#Crafter #Meetup #FRP #Agile