Why Elixir Excels at Test Driven Development

Tyler Wray
Apr 15, 2019 · 5 min read
Photo by Louis Reed on Unsplash

I joined Podium for many reasons; among them was our dedication to testing. A good test suite gives you confidence to go fast and ship code often. The Elixir ecosystem has been a wonderful environment for producing tests that give me confidence in my code. The word Elixir has its roots in testing. Elixir is defined as:

A magical or medicinal potion.

That potion was probably brewed in a lab, with a test tube. (maybe it’s a stretch but go with me here)

Test Driven Development (TDD) is a practice I use to help me write better software. The basic process of TDD is; Write a failing test, make it pass, refactor the code. Elixir has a fantastic set of tools for doing TDD.

Components of a great TDD experience

  1. Describe behaviors
  2. Excellent Error messages
  3. Mockable dependancies

Let’s look at each of these in more detail.

Fast test execution

Mix does a lot of really cool things to make your test suite fast by default, and ExUnit helps out too. Each test module you write is an elixir script, so it’s executed right away instead of compiling. Your source code is compiled, but when you run mix test it only compiles the files that have changed since your last run. Take a look at the example below of a basic test module. (Shamelessly taken from the ExUnit Docs)

Basic test example

See the async: true flag in the example? That runs this test module concurrently with other tests in your suite. Now imagine your entire test suite runs concurrently, and only compiles source code when changed 🤯

In a typical TDD workflow, running tests against a real database slows your test suite down significantly. Not with Ecto. Take a look at how fast this test suite runs with about 3/4 of the tests doing actual Database work.

🎉 1.1 seconds 😍

This is possible because Ecto itself ships with a testing sandbox mode that allows you to run concurrent tests against your database. Because sandbox mode is so fast, it’s taken away my worry of testing against a real database.

Read more about it here.

Describe Behaviors

A good pattern for labeling these describe and test blocks is to use describe for the function name its arity, then use test for each behavior that is wanted. In the example above, we wrap the test blocks in describe “add/2" saying that the add function, given two arguments, should pass these tests. Because the core building block of Elixir is just functions, all my tests follow this pattern! 🎉

The added benefit of writing our tests this way is we can target the exact behavior we want to change. It also makes for really nice error messages 😍

Test Error Message

Notice the top line there? It prefixes our test description with our describe label. This is extremely helpful if you’re going to have a test suite of significant size.

Excellent Error Messages

Elixir has the best test runner error messages of any language I’ve seen

Let’s see why.

We already showed a basic example above. But let’s examine the structure again:

The clarity of error messages in elixir is what keeps me coming back. This simple example shows its awesome power. Let’s take a look at another example that is more complex.

The Test
The Error Message

Notice how we have our assert code pulled right from our test into our error message 🙌. Elixir also used a little pattern matching magic to show us exactly where our assertions are incorrect (notice Harry Potter in green and Rubeus Hagrid in Red).

Mockable Dependancies

A good mocking solution (at minimum) allows you to set return values on a mock, see what values a mock was called with, and see how many times a mock was called.

In Conclusion


Podium’s Engineering Blog