【问题标题】:Scala and mockito to test twilio MessageFactory.create() methodScala 和 mockito 测试 twilio MessageFactory.create() 方法
【发布时间】:2015-10-04 17:29:28
【问题描述】:

我想使用一些简单的依赖注入和模拟来测试我们的 Twilio 集成。在我看来,最简单的方法是使用mockito 拦截以下消息create 调用:

val messageFactory: MessageFactory = smsProvider.getAccount().getMessageFactory()
val message: Message = messageFactory.create(params)

理想情况下,我希望将 create 调用存根,以便验证它是否被调用,并且参数是否正确。

虽然我是 Mockito 的新手,但我正在尝试拼凑如何在 Scala 中使用它(如果这种测试是可能的)。我发现的大多数示例都是用 Java 等编写的,并且不能很好地转换为 Scala。

【问题讨论】:

    标签: scala testing mocking mockito


    【解决方案1】:

    您可以在 Scala 中使用 mockito。将 mockito 添加到您的库依赖项中(例如,使用像 libraryDependencies += "org.mockito" % "mockito-core" % "1.8.5" % "test" 这样的 SBT),您就可以设置了。

    如果您使用的是 Scalatest,还有 MockitoSugar,您可以将其作为特征混合或静态导入,从而为您提供语法糖 mock[ClassToMock],而不是 mockito 的 mock(classOf[ClassToMock])

    Mockito 允许您将模拟对象作为外部依赖项传递给“被测单元”,并断言调用了某个方法。在您的情况下,外部依赖项应该是 messageFactorysmsProvider。但是,后者要求您传递 smsProvider 的存根以返回 MessageFactory 的模拟。

    您的代码可能如下所示:

    import org.mockito.Mockito.verify
    import org.mockito.Matchers.any
    import org.scalatest.FlatSpec
    import org.scalatest.mock.MockitoSugar
    
    // Your Test
    class MessageCreatorTest extends FlatSpec with MockitoSugar {
    
      val messageCreator = new MessageCreator
    
      "createMessage" should "create a new message" in {
        val factory = mock[MessageFactory]
    
        messageCreator.createMessage(factory)
    
        verify(factory).create(any[List[String]])
      }
    }
    
    // Your Unit Under Test
    class MessageCreator {
      def createMessage(messageFactory: MessageFactory): Unit ={
        messageFactory.create(List("Foo", "Bar"))
      }
    }
    
    // The external dependency of your Unit Under Test
    trait MessageFactory {
      def create(params: List[String]) = new Message("Hello")
    }
    
    // A plain value
    case class Message(message: String)
    

    但是,如果您的被测单元依赖于smsFactory,您会注意到设置测试变得更加繁重:

    import org.mockito.Mockito.{when, verify}
    import org.mockito.Matchers.any
    import org.scalatest.FlatSpec
    import org.scalatest.mock.MockitoSugar
    
    class MessageCreatorTest extends FlatSpec with MockitoSugar {
    
      val messageCreator = new MessageCreator
    
      "createMessage" should "create a new message" in {
        val factory = mock[MessageFactory]
        val account = mock[Account]
        val smsProvider = mock[SmsProvider]
        when(smsProvider.getAccount).thenReturn(account)
        when(account.getMessageFactory).thenReturn(factory)
    
        messageCreator.createMessage(smsProvider)
    
        verify(factory).create(any[List[String]])
      }
    }
    
    class MessageCreator {
      def createMessage(smsProvider: SmsProvider): Unit = {
        val messageFactory = smsProvider.getAccount.getMessageFactory
        messageFactory.create(List("Foo", "Bar"))
      }
    }
    
    trait MessageFactory {
      def create(params: List[String]) = new Message("Hello")
    }
    
    case class Message(message: String)
    
    trait SmsProvider {
      def getAccount: Account
    }
    
    trait Account {
      def getMessageFactory: MessageFactory
    }
    

    但是,在这种情况下,测试会告诉您您违反了Law of Demeter

    【讨论】:

    • 你也可以使用 specs2 trait Mockito 同时使用 scalatest code.google.com/p/specs/wiki/UsingMockito 我认为语法 smsProvider.getAccount returns account 比原来的要酷得多。
    • 我正在使用 specs2。另外,关于得墨忒耳法则:是的。但。我可以简单地模拟我自己的 Messenger 对象(它使用 Twilio 库)。但是,我真的非常想测试是否已将正确的参数传递给 Twilio,因此我正在努力寻找一种满足该需求并尽可能少地违反注入 (LoD) 原则的解决方案......
    • @kulu-limpa 看起来很棒——明天会试一试,并从 specs2 的角度提供任何反馈......谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-13
    • 2021-06-22
    相关资源
    最近更新 更多