Mockito匹配器,scala值类和NullPointerException

时间:2014-12-04 08:53:11

标签: scala mockito scalatest

我正在使用带有scalatest的mockito。使用带有值类的匹配器时,我遇到了以下问题。

import org.scalatest.FlatSpec
import org.scalatest.mock.MockitoSugar
import org.mockito.BDDMockito._
import org.mockito.Matchers.any

case class FirstId(val value: String) extends AnyVal
case class SecondId(val value: String) extends AnyVal

trait MockedClass {
  def someMethods(firstId: FirstId, secondId: SecondId): Int
}

class ValueClassSpec() extends FlatSpec with MockitoSugar {

  val mockedClass = mock[MockedClass]
  val secondId = SecondId("secondId")

  "Matchers" should "work for value class" in {
    // given
    given(mockedClass.someMethods(any[FirstId], org.mockito.Matchers.eq(secondId))).willReturn(3)
    // when
    val result = mockedClass.someMethods(FirstId("firstId"), secondId)
    // then
    assert(result == 3)
  }

}

结果是:

ValueClassSpec:
Matchers
- should work for value class *** FAILED ***
  java.lang.NullPointerException:
  at io.scalac.fow.party.ValueClassSpec$$anonfun$1.apply$mcV$sp(ValueClassSpec.scala:22)
  at io.scalac.fow.party.ValueClassSpec$$anonfun$1.apply(ValueClassSpec.scala:20)
  at io.scalac.fow.party.ValueClassSpec$$anonfun$1.apply(ValueClassSpec.scala:20)
  at org.scalatest.Transformer$$anonfun$apply$1.apply(Transformer.scala:22)
  at org.scalatest.Transformer$$anonfun$apply$1.apply(Transformer.scala:22)
  at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
  at org.scalatest.Transformer.apply(Transformer.scala:22)
  at org.scalatest.Transformer.apply(Transformer.scala:20)
  at org.scalatest.FlatSpecLike$$anon$1.apply(FlatSpecLike.scala:1639)
  ...

我发现了类似的问题(Scala Value classes and Mockito Matchers don't play together)但没有任何建议。

是否有任何可能使用scala值类的mockito匹配器?

Lib版本:scala 2.11.2,mockito 1.10.8,scalatest 2.1.6

7 个答案:

答案 0 :(得分:25)

正确的解决方案是:

case class StringValue(val text: String) extends AnyVal
case class LongValue(val value: Long) extends AnyVal

val eqFirst: StringValue = StringValue(org.mockito.Matchers.eq("first"))
val anySecond: StringValue = StringValue(org.mockito.Matchers.any[String])

val eqFirst: LongValue = LongValue(org.mockito.Matchers.eq(1L))
val anySecond: LongValue = LongValue(org.mockito.Matchers.any[Long])

答案 1 :(得分:9)

我找到了解决方案:

val anyFirstId: FirstId = any[String].asInstanceOf[FirstId]
val eqSecondId: SecondId = org.mockito.Matchers.eq[String](secondId.value).asInstanceOf[SecondId]
given(mockedClass.someMethods(anyFirstId, eqSecondId)).willReturn(3)

答案 2 :(得分:3)

这适用于所有类型的extends AnyVal值类,并且不需要特殊的匹配器:

    given(mockedClass.someMethods(FirstId(anyString), SecondId(org.mockito.Matchers.eq(secondId.value)))).willReturn(3)

答案 3 :(得分:3)

mockito-scala(0.0.9)的最新版本支持此功能,您可以执行以下操作

when(myObj.myMethod(anyVal[MyValueClass]) thenReturn "something"

myObj.myMethod(MyValueClass(456)) shouldBe "something"

verify(myObj).myMethod(eqToVal[MyValueClass](456))

免责声明:我是该库的开发人员

答案 4 :(得分:1)

如果你的依赖关系中没有形状,你可以考虑我的小助手方法:https://gist.github.com/Fristi/bbc9d0e04557278f8d19976188a0b733

而不是写

UserId(is(context.userId.value))

你可以写

isAnyVal(context.userId)

哪个更方便: - )

答案 5 :(得分:0)

我的课还扩展了AnyVal

case class ApplicationKey(value: String) extends AnyVal {
  override def toString: String = value
}

这对我有用:

   when(waterfallLogicEventWriter.writeAuctionEvents(            
     Eq(waterfallRequest.auctionId), Eq(waterfallRequest.ip),
     ApplicationKey(any[String]),                                
     any()).thenReturn(waterfallEvents) 

答案 6 :(得分:0)

如果有人正在寻找一种基于宏的解决方案,该解决方案适用于带有 private 构造函数的 AnyVal 类,这里有一些对我有用的东西:https://gist.github.com/lloydmeta/e4ba5af6dae8f1c68efc6458f0a5879d

我尝试在没有宏的情况下以“正常”方式执行此操作,但我怀疑可能会发生与字节码操作相关的事情,从而破坏了围绕函数替换的正常假设。