I’m trying to build a protocol and a test suite to implement different adapters (impls of the protocol).
I tried to use a CaseTemplate, or just regular macros, but all tests defined inside quote location: :keep ... will always show, on failure, the line where the macro is called or where the template is used.
Any idea how I could have the actual line of failure?
If I understand you right you want to see the file that defines Demo.SomeTest in the error, and if I understand the docs correctly, that’ll be the case if you remove : location.
It is the opposite. Defining location: :keep or not does not change anything. In both cases, the stacktrace is shown as test/some_test.exs:2: (test), i.e. the Demo.SomeTest module where use Demo.TestSuite is called.
I expect to see like to see the actual location of the failure: test/support/suite.ex:7: as the docs you linked suggest. (now line 10 instead of 7 in the updated version below) But somehow, a call to test inside a quote overrides this behaviour of location keep.
See this updated example:
# suite.ex
defmodule Demo.TestSuite do
use ExUnit.CaseTemplate
using do
quote do
require unquote(__MODULE__)
test "some test" do
assert 1 == 2
end
end
end
defmacro define_failing do
quote do
def failing_fun() do
ExUnit.Assertions.assert(false)
end
end
end
defmacro define_failing_with_location do
quote location: :keep do
def failing_fun_with_location() do
ExUnit.Assertions.assert(false)
end
end
end
end
# some_text.exs
defmodule Demo.SomeTest do
use Demo.TestSuite
Demo.TestSuite.define_failing()
test "macro" do
failing_fun()
end
Demo.TestSuite.define_failing_with_location()
test "macro with location" do
failing_fun_with_location()
end
end
Here we can see that with location: :keep, the actual call site for assert/1 (suite.ex:25) is reported. This is what I want.
So that would be my workaround: each test defined in the suite would contain a single external call to a function that actually implements the test. But it is convoluted for no apparent reason.
Well I don’t want to add some hackish macro code above 50 or more tests. I guess I will resort to call a test implementation function inside each test.
Hey guys, long time since this question was asked but I was just looking for the same answer and lucikly I found a workaround, in Elixir 1.18.3 (compiled with Erlang/OTP 27).
Following the recommendations from the Macros docs, this is how I’m able to get a stacktrace ending with the exact line where the assertion error is happening, in the CaseTemplate file:
defmodule Demo.TestSuite do
use ExUnit.CaseTemplate
using do
quote do
import Demo.TestSuite
test "some test" do
assert_eq(1, 2)
end
end
end
def assert_eq(a, b) do
assert a == b
true # WITHOUT this, it just shows the line in the test file at the top of the stacktrace
end
end
I’m returning true because the function starts with assert_. I would return false if the function starts with refute_
I don’t know the exact reason of this behavior, I just noticed that if the last statement in the function is an assert or refute, the output shows only the line where the function is called, and not the line inside the function.