Elixir TDD with ExUnit (interview / toy problem)

This is part one of a series on Elixir Testing.

In this episode we'll use the built-in library ExUnit to TDD our way through building a module to calculate Fibonacci numbers. We'll have two primary functions—Fibonacci.nth/1 which will return the nth number of Fibonacci sequence, and Fibonacci.first_n/1 which will return a list of the the first n numbers of the sequence.

Since the goal is to use TDD, we'll stick to a red -> green -> refactor workflow, even when optimizing for performance!

The end state for our test module:

This is what our tests look like when we're done:

defmodule FibonacciTest do
  use ExUnit.Case
  doctest Fibonacci
  @moduletag timeout: 1000

  describe "calculate the nth fibonacci number" do
    test "the first number is 1" do
      assert Fibonacci.nth(1) == 1
    end

    test "the second number is 1" do
      assert Fibonacci.nth(2) == 1
    end

    test "the third number is 2" do
      assert Fibonacci.nth(3) == 2
    end

    test "the fourth number is 3" do
      assert Fibonacci.nth(4) == 3
    end

    test "the fifth number is 5" do
      assert Fibonacci.nth(5) == 5
    end

    test "the sixth number is 8" do
      assert Fibonacci.nth(6) == 8
    end

    test "shouldn't take too long" do
      assert Fibonacci.nth(100) == Fibonacci.nth(99) + Fibonacci.nth(98)
    end
  end

  describe "calculate the first n fibonacci numbers" do
    test "doesn't return any for zero" do
      assert Fibonacci.first_n(0) == []
    end

    test "returns the first number for one" do
      assert Fibonacci.first_n(1) == [1]
    end

    test "two returns the first two numbers" do
      assert Fibonacci.first_n(2) == [1, 1]
    end

    test "6 returns the first 6 numbers" do
      assert Fibonacci.first_n(6) == [1, 1, 2, 3, 5, 8]
    end

    test "10000 isn't too slow" do
      first10k = Fibonacci.first_n(10000)
      assert Fibonacci.first_n(10001) == first10k ++ [Fibonacci.nth(10001)]
    end
  end
end

The end state for our Fibonacci module:

defmodule Fibonacci do
  @moduledoc """
  Documentation for Fibonacci.
  """

  @doc """
  Calculates numbers from the Fibonacci sequence
  ## Examples
      iex> Fibonacci.nth(1)
      1
  """

  def nth(n), do: nth(n - 1, 0, 1)
  def nth(0, _acc1, acc2), do: acc2
  def nth(n, acc1, acc2), do: nth(n - 1, acc2, acc1 + acc2)

  def first_n(n), do: first_n(n, [])
  def first_n(0, acc), do: Enum.reverse(acc)
  def first_n(n, []), do: first_n(n - 1, [1])
  def first_n(n, [1]), do: first_n(n - 1, [1, 1])

  def first_n(n, [e1 | [e2 | _tail]] = acc) do
    first_n(n - 1, [e1 + e2 | acc])
  end
end

Next episode: Fixing generated Phoenix tests

Back to index

No Comments