DEV Community

Cover image for Q&D: ExUnit and Blob Fixture in Elixir
Mathieu Kerjouan
Mathieu Kerjouan

Posted on

Q&D: ExUnit and Blob Fixture in Elixir

Another quick and dirty post regarding Elixir. This one will be really quick, but I was working on test unit recently, and was stuck for few minutes about where I could put my fixtures, and especially... some raw blobs. In Erlang, with common_test, the path is directly passed in the options and it is easy to use. In Elixir, it's a bit different, the relative path of the test suite is stored in the __DIR__ macro. This small trick get lost in my mind. Here an example.

$ mix new blob
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/blob.ex
* creating test
* creating test/test_helper.exs
* creating test/blob_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd blob
    mix test

Run "mix help" for more commands.

$ cd blob
Enter fullscreen mode Exit fullscreen mode

A fixtures directory can be helpful, let creates one.

$ mkdir -p test/fixtures
Enter fullscreen mode Exit fullscreen mode

To do the test, let create also a file called blob.txt containing an encoded string in base64 via openssl.

$ printf "this is a test" | openssl enc -base64 > test/fixture/blob.txt
Enter fullscreen mode Exit fullscreen mode

The project created for this example is a simple library, the project configuration file mix.exs must be updated to allow other files to be loaded during the test execution. This is configured in :test_load_filters section, all files ending with _test.exs and _fixtures.exs must be loaded.

defmodule Blob.MixProject do
  use Mix.Project

  def project do
    [
      app: :blob,
      version: "0.1.0",
      elixir: "~> 1.19",
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      test_load_filters: [
        &String.ends_with?(&1, "_test.exs"),
        &String.ends_with?(&1, "_fixtures.exs")
      ]
    ]
  end
  # ...
end
Enter fullscreen mode Exit fullscreen mode

An helper function to have access to the fixtures can be created. It's not mandatory, but it's easier to call something like BlobFixtures.read_blob/1 instead of recreating the same procedure everytime. DRY.

defmodule BlobFixtures do
  def read_blob(relative_path) do
    [__DIR__, "fixtures", relative_path]
    |> Path.join()
    |> File.read!()
  end
end
Enter fullscreen mode Exit fullscreen mode

The test suite can now be updated. The blob is read from the file system and pushed in the test suite.

defmodule BlobTest do
  use ExUnit.Case
  doctest Blob

  # ...

  test "read from file" do
    assert "this is a test" ==
      BlobFixtures.read_blob("blob.txt")
      |> String.trim()
      |> Base.decode64!()
      # only for the example
      |> IO.inspect()
  end
end
Enter fullscreen mode Exit fullscreen mode

Finally, mix test can be called, and it should be green. The decoded message should be printed as well.

$ mix test
Running ExUnit with seed: 423336, max_cases: 16

"this is a test"
...
Finished in 0.04 seconds (0.00s async, 0.04s sync)
1 doctest, 2 tests, 0 failures
Enter fullscreen mode Exit fullscreen mode

Indeed, it was a quick note! As usual, have fun and happy hacking!


Cover Image by Connor Gan on Unsplash

Top comments (0)