← All series

Series contents

Log in to track your progress

  1. 1. Elixir TDD with ExUnit (interview / toy problem) Episode
  2. 2. Fixing generated Phoenix tests (Trello clone P1) Episode
  3. 3. Finishing the scaffold (Trello clone P2) Episode
  4. 4. Setting up Vue and SASS (Trello clone P3) Episode
  5. 5. Integration testing Elixir with Wallaby Episode
  6. 6. Integration testing Elixir with Wallaby Part 2 Episode
  7. 7. Styling cards and todo lists (Trello clone P4) Episode
  8. 8. New cards, JSON APIs and Ajax (Trello Clone P5) Episode

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

Open standalone page ↗

No Comments