我曾经使用类似下面的习惯用ScalaCheck生成案例类:
GenSomething.map2(GenSomethingElse)(MyClass(_, _))
我们最近将ScalaCheck升级到1.11,删除了mapN
方法。我真的希望能够避免为每个字段为生成器分配中间名称,mapN
方法提供了最简单的方法。现在,最好的语法是:
for {
something <- GenSomething
somethingElse <- GenSomethingElse
} yield MyClass(
something = something,
somethingElse = somethingElse)
这不是那么糟糕(对于结构会有少量的构造函数参数),但我真的很想说明这里没有什么特别的东西,我只是为每个参数指定生成器而不是代码的读者必须通读才能确认。
简而言之,我想要一些类似于应用语法的东西。不幸的是,它不是使用scalaz,无形或宏的选项。我意识到最后一句话几乎让我的问题“如何在不能访问让我做X的事情的情况下做X”,但我希望有人能有个好主意。
答案 0 :(得分:0)
由于您明确排除了旨在防止样板的库,因此您必须使用某些样板文件。
您可以使用与Gen.resultOf类似的方法为每个arity定义gen组合器。实际上,您可以使用Gen.resultOf,因为与resultOf的唯一区别在于您希望显式提供Gen
而不是隐式提供的Arbitrary
。
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)
}