ScalaCheck:生成任意类型的任意函数

ScalaCheck: generate arbitrary functions with arbitrary types

我实现了以下功能:

/**
  * Returns a function h , which is the composition of the functions f and g.
  */
def compose[A, B, C](g: B => C, f: A => B): A => C = f.andThen(g)

我正在尝试使用 ScalaCheck 对其进行测试。我可以生成以下测试,编译并通过:

import org.scalatest.prop.PropertyChecks
import org.scalatest.{FlatSpec, Matchers}

class ComposeSpec extends FlatSpec with Matchers with PropertyChecks {

  "Compose" should "return a function h , which is the composition of the 
functions f and g" in {

    forAll { (a: Int, g: Int => Int, f: Int => Int) =>
      compose(g, f)(a) should be(g(f(a)))
    }

    forAll { (a: String, g: Double => Int, f: String => Double) =>
      compose(g, f)(a) should be(g(f(a)))
    }
  }
}

但是,如您所见,我正在生成具有已定义类型的任意函数,并将参数类型 a 与函数的输入类型 f 相匹配。我想做的是这样的:

forAll { (a: A, g: B => C, f: A => B) =>
  compose(g, f)(a) should be(g(f(a)))
}

但我不知道它的语法,也不知道它是否可能。你能帮帮我吗?

scalatest websiteforAll 有这样的说法:

An implicit Arbitrary generator and Shrink object needs to be supplied for The forAll method will pass each row of data to each parameter type. ScalaCheck provides many implicit Arbitrary generators for common types such as Int, String, List[Float], etc., in its org.scalacheck.Arbitrary companion object. So long as you use types for which ScalaCheck already provides implicit Arbitrary generators, you needn't worry about them. Same for Shrink objects, which are provided by ScalaCheck's org.scalacheck.Shrink companion object. Most often you can simply pass a property function to forAll, and the compiler will grab the implicit values provided by ScalaCheck.

所以很遗憾,您不能使用 forAll 来检查所有可能的类型,因为没有针对每种可能类型的隐式 ArbitraryShrink 对象。似乎不可能生成任何类型的任意对象。

你能做的最好的事情是:

def checkComposeForAll[A : Arbitrary : Shrink, B : Arbitrary : Shrink, C : Arbitrary : Shrink]() = {
  forAll { (a: A, g: B => C, f: A => B) =>
    compose(g, f)(a) should be(g(f(a)))
  }
}

checkComposeForAll[Int, Int, Int]()
checkComposeForAll[String, String, String]()
checkComposeForAll[List[Int], Double, Int]()
// ... etc, check a bunch of types ...