如何在Scala中分解测试中的对象功能

时间:2018-03-11 18:24:03

标签: scala unit-testing testing mocking

这是一个常见问题的通用问题,让我们尽可能简单地描述它......假设我有:

class A {
  def x() = //do something with e
  def e() = //do something else
}

基本上是一个简单的类,其中方法x()正在调用方法e()。 x()和e()的逻辑非常复杂。因此,在集成中测试它们是不切实际的(通过调用x()并断言)。通过一些嘲弄,分别测试x()e()会更容易。所以我可以去做:

abstract class A {
  def x() = {
    /* do */
  }

  def e()
}

object A {
  def eImpl() = {}

  def apply(): A = new A() {
    override def e(): Unit = eImpl()
  }
}

然后使用:

测试x()的行为
class ASpec extends FlatSpec {

  def eImpl() = {}

  def mockedA(inner: A => Unit) = {
    inner(new A {
      override def e(): Unit = ??? //some behaviour to help test, a mock, etc..
    })
  }

  "x in A" should "do this an that" in mockedA { a =>

  }

  "eImpl" should "do something else" in {

  }
}

但是......这假设伴随对象中的A()绑定了正确的实现。总而言之,这对我来说似乎有点冗长。那么有什么方法可以构建这个类以便可靠地测试并确保实例具有正确的实现?

2 个答案:

答案 0 :(得分:2)

不是spy你在寻找什么?

假设

class A {
    def x(): String = "Hello" + e()
    def e(): String = "World"
}

您可以单独模拟e()x()

import org.mockito.Mockito._
import org.scalatest.mockito.MockitoSugar
import org.scalatest.{Matchers, WordSpec}
class ASpec extends WordSpec with Matchers with MockitoSugar {
    "Spy test" should {
        "mock only e" in {
            val a = spy(new A())
            when(a.e()).thenReturn("Mock")
            a.x() shouldBe "HelloMock"
            a.e() shouldBe "Mock"
        }
        "mock only x" in {
            val a = spy(new A())
            when(a.x()).thenReturn("Yo" + a.e())
            a.x() shouldBe "YoWorld"
            a.e() shouldBe "World"
        }
    }
}

答案 1 :(得分:-1)

您可以在不使用特征引入模拟框架的情况下执行此操作。

trait A {
  def x() = "Hello " + e()
  def e() = "World"
}

class TestAX extends A {
  override def x() = super.x()
  override def e() = "Mock"
}

class TestAE extends A {
  override def x() = "Mock " + e()
  override def e() = super.e()
}

"x in A" should "do this and that" {
  val testA = new TestAX()
  assert(testA.x() == "Hello Mock")
  assert(testA.e() == "Mock")
}

"e in A" should "do something else" in {
  val testA = new TestAE()
  assert(testA.x() == "Mock World")
  assert(testA.e() == "World")
}

TestAX使用x()的生产版本并覆盖e(),或者不执行任何操作或提供要使用的测试信息(可以是常量值等)。

也就是说,如果e()和x()都相当复杂,我建议将它们分解成更小的部分,这样你就不会测试所有的工作 - >所有的工作都完成了吗?"