在 Scala 中模拟新对象的创建

Mock new object creation in Scala

我想为以下 Scala class 编写单元测试。 在下面的实现中,QueryConfig 是最终情况 class.

class RampGenerator {
  def createProfile(queryConfig: QueryConfig): String = {
    new BaseQuery(queryConfig).pushToService().getId
  }
}

我写的单元测试是这样的

@RunWith(classOf[JUnitRunner])
class RampGeneratorTest extends FlatSpec with Matchers {
  "createProfile" must "succeed" in {
    val rampGenerator = new RampGenerator()

    val queryConfig = QueryConfig("name", "account", “role")
    val baseQuery = mock(classOf[BaseQuery])
    val profile = mock(classOf[Profile])

    when(new BaseQuery(queryConfig)).thenReturn(baseQuery)
    when(baseQuery.pushToService()).thenReturn(profile)
    when(profile.getId).thenReturn("1234")
    val id = rampGenerator.createProfile(queryConfig)
    assert(id.equals("1234"))
  }
}

目前它给出了以下异常,这是预期的,因为我没有在 when 中使用模拟 class。我如何模拟新实例的创建?

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

有两种选择:

  1. 使用 powermockito 模拟构造函数(详见
  2. 外部化对象创建

关于第二个选项的更多信息 - 这实际上是一种在各种情况下都有帮助的测试技术(几个例子:你的,创建 akka actor 和断言层次结构) - 所以它可能有用放在 "toolbox".

在您的情况下,它看起来像这样:

class RampGenerator(queryFactory: QueryFactory) {
   def createProfile(queryConfig: QueryConfig) = queryFactory.buildQuery(queryConfig).pushToService().getId()
}

class QueryFactory() {
   def buildQuery(queryConfig: QueryConfig): BaseQuery = ...
}


@RunWith(classOf[JUnitRunner])
class RampGeneratorTest extends FlatSpec with Matchers {
  "createProfile" must "succeed" in {
    val rampGenerator = new RampGenerator()

    val queryConfig = QueryConfig("name", "account", “role")
    val queryFactory = mock(classOf[QueryFactory])
    val profile = mock(classOf[Profile])
    val baseQuery = mock(classOf[BaseQuery])

    when(queryFactory.buildQuery(queryConfig)).thenReturn(baseQuery)
    when(baseQuery.pushToService()).thenReturn(profile)
    when(profile.getId).thenReturn("1234")
    val id = rampGenerator.createProfile(queryConfig)
    assert(id.equals("1234"))
  }
}

请注意,查询工厂不必是 类 的单独工厂 class/hierarchy(当然 不需要 像抽象工厂这样重量级的东西模式 - 虽然你可以使用它)。特别是,我的初始版本只是使用 queryFactory: QueryConfig => BaseQuery 函数,但 mockito 不能模拟函数...

如果您更喜欢直接注入工厂方法(通过函数),Scalamock 支持模拟函数