简体   繁体   English

在Scala中模拟新对象的创建

[英]Mock new object creation in Scala

I want to write unit test for below scala class. 我想为以下scala类编写单元测试。 In the below implementation, QueryConfig is final case class. 在以下实现中,QueryConfig是最终案例类。

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

The unit test I have written is this 我写的单元测试是这个

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

Currently it gives below exception, which is expected, since I don't have mocked class used in when. 目前,它给出了以下异常,这是预料之中的,因为我没有在何时使用模拟类。 How do I mock the new instance creation? 如何模拟新的实例创建?

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

There are two options: 有两种选择:

  1. Use powermockito to mock the constructor (see this question for details) 使用powermockito模拟构造函数(有关详细信息,请参阅此问题
  2. Externalize object creation 外部化对象创建

A bit more on the second option - this is actually a testing technique that helps in a variety of situations (a couple of examples: yours, creating akka actors and asserting on hierarchies) - so it might be useful to just have it in the "toolbox". 关于第二个选项的内容要多一些-这实际上是一种测试技术,可以在多种情况下提供帮助(几个示例:您的示例,创建akka actor并声明层次结构)-因此,将其包含在“工具箱”。

In your case it'll look something like this: 在您的情况下,它将如下所示:

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

Please note query factory does not have to be a separate factory class/hierarchy of classes (and certainly does not require something as heavyweight as abstract factory pattern - although you can use it). 请注意,查询工厂不必是单独的工厂类/类的层次结构(当然,它不需要像抽象工厂模式那么重的东西-尽管可以使用它)。 In particular, my initial version was just using queryFactory: QueryConfig => BaseQuery function, but mockito cannot mock functions... 特别是,我的初始版本仅使用queryFactory: QueryConfig => BaseQuery函数,但模仿者不能模仿函数...

If you prefer to inject factory method directly (via function), Scalamock has support for mocking functions 如果您希望直接(通过函数)注入工厂方法,则Scalamock支持模拟函数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM