应用于实现 Sub-类 的 Scala 特征测试
Scala Testing of Trait Applied to Implementing Sub-Classes
鉴于实现子类
的scala特征
trait Foo {
def doesStuff() : Int
}
case class Bar() extends Foo { ... }
case class Baz() extends Foo { ... }
如何组织单元测试以测试特征并将测试应用于每个实现?
我正在寻找以下形式的内容:
class FooSpec(foo : Foo) extends FlatSpec {
"A Foo" should {
"do stuff" in {
assert(foo.doesStuff == 42)
}
}
}
然后将应用于每个实施 类:
FooSpec(Bar())
FooSpec(Baz())
如果 Bar.doesStuff
和 Baz.doesStuff
的实现有不同的行为,进行两个单独的测试是合适的解决方案。
import org.scalatest.FlatSpec
class FooSpec1 extends FlatSpec {
"a Bar" should "do a bar thing" in {
Bar().doesStuff() == 42
}
"a Baz" should "do a baz thing" in {
Baz().doesStuff() % 2 == 0
}
}
但是,如果它们具有相同的行为,您可以使用函数重构测试以避免重复代码。我不相信 scalatest 可以像您要求的那样在规范级别实现这种重用模式。
import org.scalatest.FlatSpec
class FooSpec2 extends FlatSpec {
def checkDoesStuff(foo: Foo): Boolean =
foo.doesStuff() == 42
"a Bar" should "do a bar thing" in {
checkDoesStuff(Bar())
}
"a Baz" should "do a baz thing" in {
checkDoesStuff(Baz())
}
}
属性-based 测试可以完全满足您的需求。下面是一个使用 scalacheck 的例子:
import org.scalacheck.{Gen, Properties}
import org.scalacheck.Prop.forAll
object FooProperties extends Properties("Foo"){
val fooGen: Gen[Foo] = Gen.pick(1, List(Bar(), Baz())).map(_.head)
property("a Foo always does stuff") = forAll(fooGen){
(foo: Foo) => foo.doesStuff() == 42
}
}
与 ScalaTest 规范不同,属性始终是函数。 forAll
函数接受一个生成器,对生成器的值进行采样并对所有样本运行测试。我们的生成器将始终 return Bar
或 Baz
的实例,这意味着 属性 将涵盖您要测试的所有情况。 forAll
断言,如果单个测试失败,则整个 属性 都会失败。
鉴于实现子类
的scala特征trait Foo {
def doesStuff() : Int
}
case class Bar() extends Foo { ... }
case class Baz() extends Foo { ... }
如何组织单元测试以测试特征并将测试应用于每个实现?
我正在寻找以下形式的内容:
class FooSpec(foo : Foo) extends FlatSpec {
"A Foo" should {
"do stuff" in {
assert(foo.doesStuff == 42)
}
}
}
然后将应用于每个实施 类:
FooSpec(Bar())
FooSpec(Baz())
如果 Bar.doesStuff
和 Baz.doesStuff
的实现有不同的行为,进行两个单独的测试是合适的解决方案。
import org.scalatest.FlatSpec
class FooSpec1 extends FlatSpec {
"a Bar" should "do a bar thing" in {
Bar().doesStuff() == 42
}
"a Baz" should "do a baz thing" in {
Baz().doesStuff() % 2 == 0
}
}
但是,如果它们具有相同的行为,您可以使用函数重构测试以避免重复代码。我不相信 scalatest 可以像您要求的那样在规范级别实现这种重用模式。
import org.scalatest.FlatSpec
class FooSpec2 extends FlatSpec {
def checkDoesStuff(foo: Foo): Boolean =
foo.doesStuff() == 42
"a Bar" should "do a bar thing" in {
checkDoesStuff(Bar())
}
"a Baz" should "do a baz thing" in {
checkDoesStuff(Baz())
}
}
属性-based 测试可以完全满足您的需求。下面是一个使用 scalacheck 的例子:
import org.scalacheck.{Gen, Properties}
import org.scalacheck.Prop.forAll
object FooProperties extends Properties("Foo"){
val fooGen: Gen[Foo] = Gen.pick(1, List(Bar(), Baz())).map(_.head)
property("a Foo always does stuff") = forAll(fooGen){
(foo: Foo) => foo.doesStuff() == 42
}
}
与 ScalaTest 规范不同,属性始终是函数。 forAll
函数接受一个生成器,对生成器的值进行采样并对所有样本运行测试。我们的生成器将始终 return Bar
或 Baz
的实例,这意味着 属性 将涵盖您要测试的所有情况。 forAll
断言,如果单个测试失败,则整个 属性 都会失败。