ExUnit.LetLazy
For those coming from RSpec and missing let.
Examples
Order does not matter
In the following example, note the way it’s not important what order you call
let in. The value you provide is a macro expression evaluated when it is used
via get.
defmodule AddTest do
use ExUnit.Case, async: true
use ExUnit.LetLazy
# code under test
defp add(a, b) do
a + b
end
describe "add/2 with a = b, b = 15" do
# order is not important, thanks Elixir macros
let :a, get(:b)
let :b, 15
test "gives the correct answer" do
assert add(get(:a), get(:b)) == 30
end
end
endThis is implemented using ETS.
letstores a function expressiongetpulls it out and calls it
Each test is a mashup of bits of context
Like in RSpec, you can use let to keep the LOC in your test files manageable.
Consider this example. Instead of repeating the setup each time with slight
variations, all the possible options for arguments are placed at the top, and
inside each describe block, we pull in the combination that we want to test.
What’s more, we can re-use the exact same context easily in order to test different qualities of our function - e.g. one test to make assertions about the messages it sends, a separate test to make assertions about its return value.
defmodule ReuseTest do
use ExUnit.Case, async: true
use ExUnit.LetLazy
let :a_case_1, %{large_data_structure_1a: "x"}
let :a_case_2, %{large_data_structure_2a: "x"}
let :b_case_1, %{large_data_structure_1b: "x"}
let :b_case_2, %{large_data_structure_2b: "x"}
let :call, my_function(get(:a), get(:b))
# code under test
defp my_function(a, a) do
send self(), {:log, :error, :same}
a
end
defp my_function(a, b) do
Map.merge(a, b)
end
describe "my_function, a = b" do
let :a, get(:a_case_1)
let :b, get(:a)
test "gives the correct answer" do
assert get(:call) == %{large_data_structure_1a: "x"}
end
test "sends the right message" do
get(:call)
assert_received {:log, :error, :same}
end
end
describe "my_function, a != b" do
let :a, get(:a_case_1)
let :b, get(:b_case_1)
test "does not send the message" do
get(:call)
refute_received {:log, :error, _}
end
end
describe "my_function, a case 1, b case 1" do
let :a, get(:a_case_1)
let :b, get(:b_case_1)
test "gives the correct answer" do
assert get(:call) == %{large_data_structure_1a: "x", large_data_structure_1b: "x"}
end
end
describe "my_function, a case 1, b case 2" do
let :a, get(:a_case_1)
let :b, get(:b_case_2)
test "gives the correct answer" do
assert get(:call) == %{large_data_structure_1a: "x", large_data_structure_2b: "x"}
end
end
# ... other combinations of a, b, and assertion ...
endInstallation
Add ex_unit_let_lazy to your list of dependencies in mix.exs:
def deps do
[
{:ex_unit_let_lazy, "~> 0.1.0"}
]
endThe docs can be found at https://hexdocs.pm/ex_unit_let_lazy.
See also
See also ExUnit.Let which is similar, but simpler, uses the test context
structure, and thus relies on the ordering of let calls.