【问题标题】:Mock new object creation in Scala在 Scala 中模拟新对象的创建
【发布时间】:2019-12-24 06:25:09
【问题描述】:

我想为下面的 scala 类编写单元测试。 在下面的实现中,QueryConfig 是最终的案例类。

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 中使用模拟类。如何模拟新实例的创建?

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);

【问题讨论】:

    标签: scala mocking mockito scalatest


    【解决方案1】:

    有两种选择:

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

    关于第二个选项的更多信息 - 这实际上是一种在各种情况下都有帮助的测试技术(几个例子:你的,创建 akka 演员和断言层次结构) - 所以它可能很有用在“工具箱”中。

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

    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"))
      }
    }
    

    请注意,查询工厂不必是一个单独的工厂类/类的层次结构(当然也不需要像抽象工厂模式那样重量级的东西——尽管你可以使用它)。特别是我最初的版本只是使用queryFactory: QueryConfig => BaseQuery函数,但是mockito不能mock函数...

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

    【讨论】:

    • mockito-scala 可以模拟函数 ;)
    • @Bruno 好点,谢谢!在我的辩护中,OP 没有列出使用了 mockito-scala,我也没有使用过(或遇到过它)。无论如何,我认为我还是更喜欢 scalatest,因为 mockito 在同一个 mock(包括 mockito-scala)上设置多个响应的方式比 scalamock 更不直观和更冗长
    • 我刚刚看了 scalamock 示例,它似乎更冗长且不太直观,我不知道将答案存根与您发布的 scalamock 示例进行比较是否正确,如果您喜欢在 gitter 中对我进行 ping mockito-scala 的频道,我们可以更好地讨论它:)
    猜你喜欢
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 2023-02-26
    • 2020-03-26
    • 1970-01-01
    相关资源
    最近更新 更多