I'm finding using specs2 with scalacheck to verify the Monoid laws a bit ugly when trying to make use of the scalaz scalacheck-binding library. My code uses the scalaz Monoid so I wanted to use their laws to verify my MyType implements them.
This uglyness makes me think I'm missing something or mis-using Specs2 or scalacheck-binding API's. Sugestions apreciated.
This is what i've done:-
I'm using specs2 3.7 with scalaz 2.7.0
Reading the user guide at "http://etorreborre.github.io/specs2/guide/SPECS2-3.0/org.specs2.guide.UseScalaCheck.html"
I have extended my spec with the Scalacheck
trait and I have an Arbitrary[MyType]
in scope so I should be able to use scalacheck OK.
The doc mentioned above states that I need to pass a function to the prop
method as long as the passed function returns a Result
where scalacheck's Prop
is a valid Result
The scalacheck-binding api gives me a monoid.laws[T]
function that returns a Properties
which is a Prop
so this should be OK, it also takes implicit parameters of types Monoid[T]
, Equal[T]
and Arbitrary[T]
all of which I have in scope where T
is MyType
I want to do this:
class MyTypeSpec extends Specification with ScalaCheck {
def is = s2"""
MyType spec must :-
obey the Monoid Laws $testMonoidLaws
"""
def testMonoidLaws = {
import org.scalacheck.{Gen, Arbitrary}
import scalaz.scalacheck.ScalazProperties._
implicit val arbMyType: Arbitrary[MyType] = genArbMyTpe() // an helper Arbitrary Gen func i have written
prop { monoid.laws[MyType] }
}
}
but prop
cannot be applied to (org.scalacheck.Properties)
It requires the T in the Arbitrary to be the type in the parameter to the function, so I have done this, notice I trow away the parameter t, ...
class MyTypeSpec extends Specification with ScalaCheck {
def is = s2"""
MyType spec must :-
obey the Monoid Laws $testMonoidLaws
"""
def testMonoidLaws = {
import org.scalacheck.{Gen, Arbitrary}
import scalaz.scalacheck.ScalazProperties._
implicit val arbMyType: Arbitrary[MyType] = genArbMyTpe() //some Arbitrary Gen func
prop { (t: Path => monoid.laws[MyType] }
}
}
My test passes. yay! So What's the problem?
I'm uneasy about the test. All it says is it passed. I get no output like I would if using Scalacheck directly telling me which laws it ran and passed.
Also I throw away the parameter t
and let monoid.laws[MyType]
find the in scope implicits, which just seems wrong. Is it working? have I mangled the specs2 API?
modifying MyType so it would definatly fail the laws caused the test to fail, which is good but I am still uneasy as it always fails with
Falsified after 0 passed tests.
I can collect the Arbitrary[MyType] by doing
prop { (p: Path) => monoid.laws[Path] }.collectArg(f => "it was " + f.shows)
then running it like so
sbt testOnly MyTypeSpec -- scalacheck.verbose
which shows me the collected values of t
when it works but as I throw away t
I'm not sure if this is valid at all.
Is there a better way to test using Specs2 and the scalaz scalacheck-bindings that is less ugly and outputs info that give me confidence that Laws were tried and tested?
Thanks
Karl