How do I provide a Position
to org.scalatest.Assertions.assert
so that it reports a different position rather that the default one?
My problem is that I have a parent test class and a child test class. The child test class uses an assertion method in parent. This causes the test fail messages to be pointed to the parent method instead of the child method.
For example, I have a parent test class as:
abstract class ParentSpec[A <: TestSubject] extends FunSuite {
protected def checkId(underTest: => A, expectedId: Int): Assertion = {
assert(underTest.id == expectedId)
}
}
And a child test class as:
class FooSpec extends ParentSpec[Foo] {
test("check id") {
checkId(Foo(1, 2, 3), 999) // this fails
}
}
If the test fails, then the assertion reports that the issue is from ParentSpec.scala
. How can I change this to FooSpec.scala
?
I noticed that assert
takes in an implicit Position
def assert(condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position): Assertion
can I somehow provide the position?
Just make the checkId
method also accept an implicit position:
protected def checkId(underTest: => A, expectedId: Int)(implicit pos: Position): Assertion
That's it. Now the messages should point at invocations of checkId
(unless it's called from yet another function with its own position parameter).
Now a few words about how this works:
It's all based on where the compiler looks for implicits. The implicit Position
is needed for your assert
call which is inside checkId
. If checkId
accepts an implicit Position
parameter by itself, that parameter is simply passed forward to assert
. But when this parameter is absent, the compiler will fall back to Position.here
(defined in Position
companion object). This thing is a macro which materializes the position at which it is called.