2 minutes
Using the pipe operator in Elixir test assertions with ExUnit
Love the pipe operator? Miss them in tests with ExUnit
when the result is derived from a pipeline of operations necessitating an intermediate variable, like result
? I did…
typical test assertion (no pipe operator)
defmodule AdderTest do
test "add" do
result =
1..3
|> Enum.map(& &1 * 2) # [2, 4, 6]
|> Adder.add(1) # [3, 5, 7]
assert result == [3, 5, 7]
end
end
verbose (with pipe)
We can employ an anonymous function (lambda). NOTE: invoked with dot-syntax
defmodule AdderTest do
test "add" do
1..3
|> Enum.map(& &1 * 2)
|> Adder.add(1)
|> (fn result -> assert result == [3, 5, 7] end).()
end
end
terse (with pipe)
This uses Elixir’s & (capture operator) to keep things concise
defmodule AdderTest do
test "add" do
1..3
|> Enum.map(& &1 * 2)
|> Adder.add(1)
|> (& assert &1 == [3, 5, 7]).()
end
end
an option for those that use Elixir’s formatter
If you or your team use Elixir’s formatter, then you’re going to end up with something like the following where the nice whitespace that gives your arguments some room to breathe is removed. One thing that I’ve done is add two enhancement functions (using a macros) into test/test_helper.exs
that become available to tests by invoking use TestHelper
defmodule AdderTest do
test "add" do
1..3
|> Enum.map(& &1 * 2)
|> Adder.add(1)
|> (&assert(&1 == [3, 5, 7])).() # 🤮
end
end
Here’s what we can do
# test/test_helper.exs
ExUnit.start()
defmodule TestHelper do
defmacro __using__(_opts) do
quote do
import ExUnit.Assertions, only: [assert: 1]
# we can name this whatever we'd like,
# but "is" makes sense to me in most cases
# 👇
def is(result, expectation) do
assert result == expectation
result # 👈 allows us to continue chaining assertions in a pipeline
end
# this one allows us to make more complex assertions
# e.g., asserting that a nested key is of a particular value
def has(result, assertion) when is_function(assertion) do
assert assertion.(result) == true
result
end
end
end
end
# test/adder_test.exs
defmodule AdderTest do
use TestHelper # 👈 included here
test "add" do
1..3
|> Enum.map(& &1 * 2)
|> Adder.add(1)
|> is([3, 5, 7]) # 👈 used here
|> has(&List.last(&1) == 7) # 👈 and here (chained)
end
end
Read other posts
comments powered by Disqus