This article was originally published on Medium.

Introduction

TL;DR If you came here only for the technical article, please jump to the next section. If you are curious about who am I and why I start publishing here, you can continue reading this introduction.

This is my first article on medium, so I thought it would be a good idea to start it with an introduction. I will present myself, who am I, what I do, and what you can expect to appear on this blog.

My name is Jean-Philippe Cugnet. I’m a 23 years old software engineer and photographer, living in Caen, France. I just got a Master degree in IT Security at the University of Caen and I’m currently working as an embedded software developer in a design house. I also love film photography a lot, making photos from little things people may not care about. The photography story goes on my website. The technical one continues here.

I came to Elixir six months ago—in March 2017—as a way to help me develop web applications. I knew PHP for a while, but wasn’t too good in web development. To really start doing great things, I had to choose something that would make the development process enjoyable. I thought for a long time about trying Ruby on Rails, but I’d read it was no longer a killer framework on the performance side. The hype is clearly towards Javascript these days, so I started to view fullstack JS and things like MEAN as a good option. But then I said to me front-end frameworks are a good option only for application that need Javascript. Not for rendering simple applications. At the same time, I read people on forums talking about Elixir scaling better than Javascript and being ready for concurrent programming. This was not in my needs, but it would be valuable anyway to learn something that is future-proof.

I run a server on which I installed eJabberd, an XMPP server written in Erlang. Curious about the language, I read its article on Wikipedia a while ago. I said to myself it would be fun to learn it some day. Then, in one of the eJabberd’s changelogs, I’ve seen something about Elixir. I did not particularly notice at the time, but reading again about it while looking for something new to learn did tilt. Then I came to Phoenix, and here am I.

I currently run one Phoenix application in “production” to help me organise parties with friends. I also played a bit with soft-realtime features provided by the Phoenix channels to remotely control an embedded system, and I’m now starting a new project to help film photographers manage their rolls of film, from stock to archives.

I’m starting this blog for sharing my solution to an issue I’ve already run into twice. I thought many times to start a blog to tell about different things. This time, I feel confident enough to start with this subject I really love: coding in Elixir. Many articles here will deal with software development, but I may also share my thoughts, ideas an knowledge about many other subjects. I may post often or not, I frankly don’t know. We’ll see.

The problem

A few days ago, I started to write kakte, my second Phoenix application with contexts. This is also the second time I’ve run into the same little problem: sharing fixtures across test modules. In fact, when you generate a new schema in Phoenix, you end up with close test fixtures in two different places.

First, you write the tests for the context with valid attributes:

defmodule Kakte.AccountsTest do
  use Kakte.DataCase

  alias Ecto.Changeset
  alias Kakte.Accounts

  describe "[users]" do
    alias Kakte.Accounts.User

    @password "U[.2)hkvL!6<"
    @valid_attrs %{
      username: "user",
      email: "user@kakte.io",
      password: @password,
      password_confirmation: @password,
      fullname: "John Smith",
    }

    @new_password "s0jH,Fst;HQm"
    @update_attrs %{
      username: "new_user",
      email: "new_user@kakte.io",
      password: @new_password,
      password_confirmation: @new_password,
      fullname: "Fred Smith",
    }

    @invalid_attrs %{
      username: nil,
      email: nil,
      password: nil,
      password_confirmation: nil,
      fullname: nil,
    }

    def user_fixture(attrs \\ %{}) do
      {:ok, user} =
        attrs
        |> Enum.into(@valid_attrs)
        |> Accounts.register

      user
    end

    test "list_users/0 returns all users" do
      user = user_fixture()
      assert Accounts.list_users == [user]
    end

    [...]
  end
end

Then, you want to write some tests for the controller:

defmodule KakteWeb.UserControllerTest do
  use KakteWeb.ConnCase

  alias Kakte.Accounts

  @password "U[.2)hkvL!6<"
  @valid_attrs %{
    username: "user",
    email: "user@kakte.io",
    password: @password,
    password_confirmation: @password,
    fullname: "John Smith",
  }

  @new_password "s0jH,Fst;HQm"
  @update_attrs %{
    username: "new_user",
    email: "new_user@kakte.io",
    password: @new_password,
    password_confirmation: @new_password,
    fullname: "Fred Smith",
  }

  @invalid_attrs %{
    username: nil,
    email: nil,
    password: nil,
    password_confirmation: nil,
    fullname: nil,
  }

  def fixture(:user) do
    {:ok, user} = Accounts.register(@create_attrs)
    user
  end

  [...]
end

There is here a lot of code duplication! This is not great to write, and worse to maintain. What if I want to add an attribute to my users, like a role? I must update two files and that’s not really fun to do.

My solution

My solution to this problem has been to create a new module in test/support/fixtures.ex. It aims to provide fixtures for whatever schema you want, just by using it:

defmodule Kakte.Fixtures do
  @moduledoc """
  A module for defining fixtures that can be used in tests.
  This module can be used with a list of fixtures to apply as parameter:
      use Kakte.Fixtures, [:user]
  """

  def user do
    alias Kakte.Accounts

    quote do
      @password "U[.2)hkvL!6<"
      @valid_attrs %{
        username: "user",
        email: "user@kakte.io",
        password: @password,
        password_confirmation: @password,
        fullname: "John Smith",
      }

      @new_password "s0jH,Fst;HQm"
      @update_attrs %{
        username: "new_user",
        email: "new_user@kakte.io",
        password: @new_password,
        password_confirmation: @new_password,
        fullname: "Fred Smith",
      }

      @invalid_attrs %{
        username: nil,
        email: nil,
        password: nil,
        password_confirmation: nil,
        fullname: nil,
      }

      def user_fixture(attrs \\ %{}) do
        {:ok, user} =
          attrs
          |> Enum.into(@valid_attrs)
          |> Accounts.register

        user
      end
    end
  end

  @doc """
  Apply the `fixtures`.
  """
  defmacro __using__(fixtures) when is_list(fixtures) do
    for fixture <- fixtures, is_atom(fixture),
      do: apply(__MODULE__, fixture, [])
  end
end

Then, in my tests I am able to use them:

defmodule Kakte.AccountsTest do
  use Kakte.DataCase

  alias Ecto.Changeset
  alias Kakte.Accounts

  describe "[users]" do
    use Kakte.Fixtures, [:user] # The fixtures for User are imported here

    alias Kakte.Accounts.User

    test "list_users/0 returns all users" do
      user = user_fixture()
      assert Accounts.list_users == [user]
    end

    [...]
  end
end

If I need to import fixtures for several schemas in the future, I’ll be able to do so by defining them in fixtures.ex and passing the atoms as a list to the use statement:

use Kakte.Fixtures, [:user, :film_roll]

Conclusion

I hope this little article will be helpful to some of you in your search for writing better code. To Elixir developers with more experience: how do you solve this issue? Is there a better way to do it? Don’t hesitate to share your thoughts on this in the comments.