How to ignore test utility methods when scalatest detects failures?

I have this convenience method in my tests:

def assertFormat[T: SexpFormat](start: T, expect: Sexp): Unit = { val sexp = start.toSexp assert(sexp === expect, s"${sexp.compactPrint} was not ${expect.compactPrint}") expect.convertTo[T] should be(start) } 

which is basically convenient for running an approval template, which I do a lot.

It is not possible to rewrite this as a Matcher due to the implicit requirement for SexpFormat[T] (although I would be interested to know how to do this, which does not require me to write the MyFormat type in foo should roundTrip[MyFormat](...) )

If any tests are not performed inside this utility method, scalatest will mark the internal assertFormat elements as the cause of the test failure. But I really want the scaler to detect the calling method in order to be the cause of the test. How can i do this?

i.e. current output

 [info] - should support custom missing value rules *** FAILED *** [info] SexpNil did not equal SexpCons(SexpSymbol(:duck),SexpCons(SexpNil,SexpNil)) nil was not (:duck nil) (FormatSpec.scala:11) [info] org.scalatest.exceptions.TestFailedException: [info] at org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:529) [info] at org.scalatest.FlatSpec.newAssertionFailedException(FlatSpec.scala:1691) [info] at org.scalatest.Assertions$AssertionsHelper.macroAssert(Assertions.scala:502) [info] at org.ensime.sexp.formats.FormatSpec$class.assertFormat(FormatSpec.scala:11) [info] at org.ensime.sexp.formats.test.FamilyFormatsSpec.assertFormat(FamilyFormatsSpec.scala:151) [info] at org.ensime.sexp.formats.test.FamilyFormatsSpec.roundtrip(FamilyFormatsSpec.scala:156) [info] at org.ensime.sexp.formats.test.FamilyFormatsSpec$$anonfun$12.apply(FamilyFormatsSpec.scala:222) [info] at org.ensime.sexp.formats.test.FamilyFormatsSpec$$anonfun$12.apply(FamilyFormatsSpec.scala:221) 

FormatSpec.scala:11 is where my assertFormat . The real failure is in FamilyFormatsSpec.scala:222 (which calls another convenience method FamilyFormatsSpec.scala:156 )

+6
source share
1 answer

This is possible in ScalaTest 3.0 by taking the implicit org.scalactic.source.Position in your custom statement. Then the position will be calculated (via a macro) whenever you call the assertFormat method, and this position will be picked up by the assert and matcher expression inside assertFormat . Here's what it looks like:

 import org.scalactic.source def assertFormat[T: SexpFormat](start: T, expect: Sexp)(implicit pos: source.Position): Unit = { val sexp = start.toSexp assert(sexp === expect, s"${sexp.compactPrint} was not ${expect.compactPrint}") expect.convertTo[T] should be(start) } 

The following example shows this. If you have ScalaTest 3.0 on the class path, simply: load the following file into the Scala REPL:

 :paste import org.scalatest._ import org.scalactic._ import Matchers._ case class Sexp(o: Any) { def compactPrint: String = o.toString def convertTo[T: SexpFormat]: Sexp = implicitly[SexpFormat[T]].convertIt(o) override def toString = "I'm too sexp for my shirt." } trait SexpFormat[T] { def convertIt(o: Any): Sexp = new Sexp(o) } implicit class Sexpify(o: Any) { def toSexp: Sexp = new Sexp(o) } implicit def universalSexpFormat[T]: SexpFormat[T] = new SexpFormat[T] {} def assertFormat[T: SexpFormat](start: T, expect: Sexp): Unit = { val sexp = start.toSexp assert(sexp === expect, s"${sexp.compactPrint} was not ${expect.compactPrint}") expect.convertTo[T] should be(start) } import org.scalatest.exceptions.TestFailedException val before = intercept[TestFailedException] { assertFormat(1, new Sexp) } println(s"${before.failedCodeStackDepth} - This stack depth points to the assert call inside assertFormat") import org.scalactic.source def betterAssertFormat[T: SexpFormat](start: T, expect: Sexp)(implicit pos: source.Position): Unit = { val sexp = start.toSexp assert(sexp === expect, s"${sexp.compactPrint} was not ${expect.compactPrint}") expect.convertTo[T] should be(start) } val after = intercept[TestFailedException] { betterAssertFormat(1, new Sexp) } println(s"${after.failedCodeStackDepth} - This stack depth is the betterAssertFormat call itself in your test code") 

He will print:

 3 - This stack depth points to the assert call inside assertFormat 4 - This stack depth is the betterAssertFormat call itself in your test code 
+2
source

All Articles