2016-01-06 21 views
2

我正在使用specs2与scalacheck来验证Monoid法则在尝试使用scalaz scalacheck绑定库时发现有点难看。 我的代码使用了Scalaz Monoid,所以我想用他们的法则来验证我的MyType实现它们。使用specs2与scalaz-scalacheck绑定来测试法律

这种丑陋让我觉得我错过了某些东西或者错误地使用了Specs2或者scalacheck绑定API。取消预计。

这是我做了什么: -

我使用specs2 3.7与scalaz 2.7.0

在“http://etorreborre.github.io/specs2/guide/SPECS2-3.0/org.specs2.guide.UseScalaCheck.html” 我已延长我的规格与Scalacheck特质阅读用户指南我有一个Arbitrary[MyType]的范围,所以我应该可以使用scalacheck确定。

上面,我需要那么长的一个函数传递给prop方法传递的功能状态中提到的文档返回Result其中scalacheck的Prop是一个有效的Result

的scalacheck结合API给了我一个monoid.laws[T]功能返回一个Properties这是一个Prop所以这应该是好的,它也需要的类型Monoid[T]Equal[T]Arbitrary[T]我全部都在范围隐含参数,其中,TMyType

我想这样做:

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] } 
    } 
} 

propcannot be applied to (org.scalacheck.Properties) 它需要在任意的T是在参数给函数的类型,所以我已经这样做了,请注意我特罗远参数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] } 
    } 
} 

我的测试通过。好极了!所以有什么问题?

我对测试感到不安。它说的是它通过了。如果使用Scalacheck直接告诉我它运行并通过了哪些规则,那么我不会得到任何输出。 此外,我扔掉参数t,并让monoid.laws[MyType]找到范围内的含义,这似乎是错误的。它工作吗?我是否损伤了specs2 API?

修改的MyType所以它会definatly失败的规律导致测试失败,这是好的,但我仍然感到不安,因为它总是失败,

Falsified after 0 passed tests. 

我可以做

收集任意[MyType的]
prop { (p: Path) => monoid.laws[Path] }.collectArg(f => "it was " + f.shows) 

然后运行它像这样

sbt testOnly MyTypeSpec -- scalacheck.verbose 

其示出了箱的0所收集的值当它工作,但当我扔掉t我不知道这是否有效。

有没有更好的方法来测试使用Specs2和scalaz scalacheck绑定是不是很难看,并输出信息,让我相信法律已经过测试和测试?

感谢

卡尔

回答

3

您可以直接使用Properties,而不必使用prop。这是一个完整的例子:

import org.specs2._ 
import scalaz.scalacheck.ScalazProperties._ 
import org.scalacheck._ 
import scalaz._, Scalaz._ 
import PositiveInt._ 

class TestSpec extends Specification with ScalaCheck { def is = s2""" 

PositiveInt should pass the Monoid laws $e1 

""" 
    def e1 = monoid.laws[PositiveInt] 
} 

case class PositiveInt(i: Int) 

object PositiveInt { 
    implicit def ArbitraryPositiveInt: Arbitrary[PositiveInt] = 
    Arbitrary(Gen.choose(0, 100).map(PositiveInt.apply)) 

    implicit def EqualPositiveInt: Equal[PositiveInt] = 
    Equal.equalA[PositiveInt] 

    implicit def MonoidPositiveInt: Monoid[PositiveInt] = new Monoid[PositiveInt] { 
    val zero = PositiveInt(1) 
    def append(p1: PositiveInt, p2: =>PositiveInt): PositiveInt = 
     PositiveInt(p1.i + p2.i) 
    } 
} 

而且由于Monoid实例是不正确使用它会失败:

[info] TestSpec 
[info] 
[error] x PositiveInt should pass the Monoid laws 
[error] Falsified after 0 passed tests. 
[error] > Labels of failing property: 
[error] monoid.left identity 
[error] > ARG_0: PositiveInt(3) 
[info] 
[info] 
[info] Total for specification TestSpec 
[info] Finished in 185 ms 
[info] 1 example, 1 failure, 0 error 

的失败表明,未能通过第一定律。然而,它并没有创造出几个例子,每个法律都有一个例子来显示哪个法律正在执行。如果你想这样做,你可以映射的法律Properties一个实例每个属性: 类TestSpec扩展与ScalaCheck规格{高清是= S2“””

PositiveInt should pass the Monoid laws $properties 

""" 

    def properties = toExamples(monoid.laws[PositiveInt]) 

    def toExamples(ps: Properties): Fragments = 
    t^Fragments.foreach(ps.properties) { case (name, prop) => br^name ! prop } 
} 

此照片(用于传递Monoid[PositiveInt]实例) :

[info] TestSpec 
[info] 
[info] PositiveInt should pass the Monoid laws 
[info] + monoid.semigroup.associative 
[info] + monoid.left identity 
[info] + monoid.right identity 
[info] 
[info] Total for specification TestSpec 
[info] Finished in 91 ms 
[info] 3 examples, 300 expectations, 0 failure, 0 error 
+0

谢谢埃里克我不清楚,我可以直接从所有示例使用prop的文档直接返回属性。 – user2056182