Scala,Specs2和共享状态

时间:2019-05-21 06:47:35

标签: scala testing specs2

我正在编写一些 Specs2 规范;看起来像这样:

class ComponentSpecification extends Specification with Mockito {

  private val dependency = mock[Dependency]
  private val subject = new Component(..)

  "methodOne" should {
    "handle happy path" in {
       val result = subject.methodOne("Param1", 42)
       result must ...
       there was one(dependency).something()
    }

    "deal with border case" in {
       val result = subject.methodOne("", -1)
       result must ...
       there was one(dependency).something()
    }
  }
}

但是,由于mock[Dependency]是共享的,所以这些测试失败。

  • 一种解决方案是使它们具有顺序性,并在每次测试之前重置模拟,但这看起来很奇怪,并且在文档中有关“默认情况下为平行”
  

当给定示例的结果不应受到他人影响时,鼓励编写独立的示例

  • 另一种方法是将val移至测试本身。但是尽管我应该能够减少重复,但这仍然看起来很奇怪。并且看起来subject是有状态的,而实际上却没有。

  • 我也可以尝试使用不太严格的方法,方法是使用there was atLestOne(dependency).something()进行验证,但是:

    1. 这不能验证是否在此特定测试用例中调用了该方法,并且
    2. 参数捕获和验证很痛苦。

所以我的问题是:

如何通过对模拟的详细验证来创建可读性测试。

非常感谢。

2 个答案:

答案 0 :(得分:2)

Scopes可以像这样为每个测试提供新状态

class ComponentSpecification extends mutable.Specification with Mockito {
  trait FooScope extends Scope {
    val dependency = mock[Dependency]
    val subject = new Component(dependency)
  }

  "methodOne" should {
    "handle happy path" in new FooScope {
      val result = subject.methodOne("Param1", 42)
      there was one(dependency).something()
    }

    "deal with border case" in new FooScope {
      val result = subject.methodOne("", -1)
      there was one(dependency).something()
    }
  }
}

无需在每次测试前重置模拟。

答案 1 :(得分:0)

我要接受@Mario Galic的回答。但是,关于@Eric(Specs2的作者)的评论,我以一种按预期方式创建上下文但删除重复项的方法结束。通过使用模式匹配,我提取了有趣的部分:

class ComponentSpecification extends mutable.Specification with Mockito {
  def givenOneCallToMethodOneWithDependency(s:String, i:Int):(Result, Dependency) = {
    val dependency = mock[Dependency]
    val subject = new Component(dependency)
    val result = subject.methodOne(s, i)
    (result, dependency)
  }

  "methodOne" should {
    "handle happy path" in new FooScope {
      val (result, dependency) = givenOneCallToMethodOneWithDependency("Param1", 42)
      there was one(dependency).something()
    }

    "deal with border case" in new FooScope {
      val (result, dependency) = givenOneCallToMethodOneWithDependency("", -1)

      there was one(dependency).something()
    }
  }
}