2

我曾经使用类似下面的习语来使用 ScalaCheck 生成案例类:

GenSomething.map2(GenSomethingElse)(MyClass(_, _))

我们最近将 ScalaCheck 升级到 1.11,删除了这些mapN方法。我真的希望能够避免必须为每个字段的生成器分配中间名称,并且这些mapN方法提供了最简单的方法来做到这一点。现在,最好的语法是:

for {
  something <- GenSomething
  somethingElse <- GenSomethingElse
} yield MyClass(
  something = something,
  somethingElse = somethingElse)

这还不错(因为结构将包含少量的构造函数参数),但我真的想明确一点,这里没有什么特别的,我只是为每个参数指定生成器,而没有读者代码必须通读以确认。

简而言之,我想要类似于应用语法的东西。不幸的是,不能选择使用 scalaz、shapeless 或宏。我意识到最后一句话几乎让我的问题是“我怎么能做 X 没有访问让我做 X 的事情”,但我希望有人会有一个好主意。

4

1 回答 1

0

由于您明确排除了旨在防止样板文件的库,因此您将不得不使用一些样板文件。

您可以使用与 Gen.resultOf 类似的方法为每个 arity 定义 gen 组合器。实际上,您可以只使用 Gen.resultOf,因为与 resultOf 的唯一区别是您想要显式提供Gen的 s 而不是隐式提供Arbitrary的 s。

object GenCombiner {

  def zipMap[A, R](a: Gen[A])(f: A ⇒ R): Gen[R] =
    Gen.resultOf(f)(Arbitrary(a))

  def zipMap[A, B, R](a: Gen[A], b: Gen[B])(f: (A, B) ⇒ R): Gen[R] =
    Gen.resultOf(f)(Arbitrary(a), Arbitrary(b))

  def zipMap[A, B, C, R](a: Gen[A], b: Gen[B], c: Gen[C])(f: (A, B, C) ⇒ R): Gen[R] =
    Gen.resultOf(f)(Arbitrary(a), Arbitrary(b), Arbitrary(c))

  // other arities
}

object GenCombinerTest {
  import GenCombiner._

  case class Foo(alpha: String, num: String)

  val fooGen: Gen[Foo] = zipMap(Gen.alphaStr, Gen.numStr)(Foo)
}
于 2015-11-03T10:46:24.897 回答