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

Testing becomes much nicer when you can describe the intended behavior of your code with words. ExUnit gives us two macros for describing behavior: describe and test . These two macros are the building blocks of our tests. Here’s a contrived example of how you could use describe and test together:

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

Why do error messages help with TDD? The first step of TDD is important: make a failing test. Not only should the test fail, but it should be made to fail in exactly the way you want. I’ll be bold here:

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: