特征的Scala测试应用于实现子类

问题描述 投票:1回答:1

给出了实现子类的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())
scala scalatest
1个回答
0
投票

如果Bar.doesStuffBaz.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())
  }

}

基于属性的测试可以完全满足您的需求。以下是使用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函数接受一个生成器,对发生器的值进行采样并对所有样本运行测试。我们的生成器将始终返回BarBaz的实例,这意味着该属性将涵盖您要测试的所有案例。 forAll断言,如果单个测试失败,整个属性都会失败。

© www.soinside.com 2019 - 2024. All rights reserved.