/ Bit by bit / posts

Custom ExUnit.CaseTemplate

Aug 9, 2018

Creating custom ExUnit.Case is done simply by creating a module that use ExUnit.CaseTemplate. However, doing just that is not enough: when I run mix test, the terminal shows the following:

$ mix test
Compiling 1 file (.ex)
Generated dna app

== Compilation error in file test/my_test.exs ==
** (CompileError) test/my_test.exs:2: module MyCase is not loaded and could not be found
    (elixir) expanding macro: Kernel.use/1
    test/my_test.exs:2: MyTest (module)
    (elixir) lib/code.ex:767: Code.require_file/2
    (elixir) lib/kernel/parallel_compiler.ex:209: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6

(Yeah, I know, I admit: I’m a noob).

The missing piece is configuring Mix. mix test is a task that only compiles source under lib directory before running tests; it does not compile sources in test directory. Because the custom case in tests is a module1, Mix needs to know it has to include another directory when compiling tests:

defmodule My.MixProject do
  use Mix.Project

  def project do
    [
      app: :my,
      version: "0.1.0",
      elixirc_paths: elixirc_paths(Mix.env())
    ]
  end

  defp elixirc_paths(:test), do: ["lib", "test"]
  defp elixirc_paths(_),     do: ["lib"]
end

:elixirc_paths defaults to "lib", hence, the need to make changes similar to the highlighted lines to make custom cases work.

Edit: Update post to reflect new understanding of how Mix works [2021-02-14]


  1. The custom case module must end with a .ex extension, not .exs↩︎