Surprises in Java's Math class
ScalaTest/ScalaCheck has a rather nice little feature. It can boundary check your unit tests. Let's take this code:
import org.scalatest.WordSpec
import org.scalatest.prop.GeneratorDrivenPropertyChecks
import org.scalatest.Matchers
class MyScalaTest extends WordSpec with GeneratorDrivenPropertyChecks with Matchers {
"java.lang.Math.abs" should {
"always return a non-negative value" in {
forAll { x: Int =>
Math.abs(x) should be >= 0
}
}
}
}
It nicely runs the test many times, probing it with different values. Unfortunately, it fails with:
[info] MyScalaTest:
[info] Math.abs
[info] - should always return a non-negative value *** FAILED ***
[info] TestFailedException was thrown during property evaluation.
[info] Message: -2147483648 was not greater than or equal to 0
[info] Location: (MyScalaTest.scala:12)
[info] Occurred when passed generated values (
[info] arg0 = -2147483648
[info] )
What? How could java.lang.Math.abs fail to return a non-negative value? Well, we hit a boundary condition. ScalaCheck is clever enough to try Integer.MIN_VALUE. However, because there are more negative Integers than positive (the range is -231 to 231-1), not all negative integers map to positive ones.
If we are happy with a limited range, we can write:
import org.scalacheck.Gen
.
.
val sensibleRange = Gen.choose(0, 100)
forAll(sensibleRange) {
.
.
to choose numbers inclusive of 0 to 99.
No comments:
Post a Comment