我有一个单元测试,测试一些解决方案。但是这个测试代码也可以用于测试另一个非常相似的解决方案。我想要做的是测试代码是通用的,可以应用于这两种解决方案,如下所示:
describe("when table contains all correct rows") {
it("should be empty") {
def check[T](func: T => List[Row]) = {
val tableGen = new TableGenerator()
val table: Vector[Row] = tableGen.randomTable(100)
.sortWith(_.time isBefore _.time).distinct
val result: List[Row] = func(table)
assert(result.isEmpty)
}
check(Solution.solution1)
check(Solution.solution2)
}
}
解决方案有类型:
solution1: IndexedSeq[Row] => List[Row]
solution2: Seq[Row] => List[Row]
如何编写 check()函数才能做到这一点? 什么是最好的方法来编写这个(可能以其他方式)消除代码重复?
更新
当我尝试编译此代码时,我在func(table)
:
Error:(36, 29) type mismatch;
found : table.type (with underlying type scala.collection.immutable.Vector[com.vmalov.tinkoff.Row])
required: T
val result = func(table)
答案 0 :(得分:4)
为此,您需要能够将Vector[Row]
传递给func
,因此任何Vector[Row]
都必须是T
;也就是说,T
是Vector[Row]
的超类型。您可以使用绑定的类型参数来告诉编译器:
def check[T >: Vector[Row]](func: T => List[Row])
或者,通过上述推理,当T => List[Row]
是Vector[Row] => List[Row]
的超类型时,函数T
也将是函数Vector[Row]
,并且Scala编译器知道这(函数在其参数类型中是逆变)。所以这个签名相当于更简单的
def check(func: Vector[Row] => List[Row])
当然,你可以概括一下,但多少取决于你的具体愿望。例如。您可以将List[Row]
替换为Seq[Row]
(无处不在),或使用类型参数替换,并将额外的函数传递给check
:
def check[A](func: Vector[Row] => A)(test: A => Boolean) = {
val table = ...
val result = func(table)
assert(test(result))
}
check(Solution.solution1)(_.isEmpty) // the compiler infers A is List[Row]
答案 1 :(得分:3)
您的情况,也许足以以更具体的方式抽象类型,例如定义您期望Travesable。
def check[S[_] : Traversable](func: S[Row] => List[Row])
这会接受Seq或IndexedSeq作为有效参数,同时也会限制它。
我希望它有所帮助
编辑:检查Alexey Romanov答案,就像这样,你将无法以你的方式调用func。抱歉,
def check(func:Vector [Row] => List [Row])