使用 Mockito 监视带有对象参数的方法导致 NullPointerException

kri*_*ath 1 scala nullpointerexception mockito scalatest

我正在尝试测试一些代码,Mockito.spy用于为我需要提供的某些功能提供行为。虽然我知道我正在做的事情可能有更好的替代方案,但我很好奇为什么下面的代码NullPointerException在 Scala 中抛出 a以及如何解决它。

该类Foo正在测试中。它包含一个方法act,就这个问题而言,它只计算数字的总和。ClassFooSpec是class的相应单元测试Foo。ClassBar是另一个类,用作 class 的参数Foo以演示出现异常的情况。

以下代码有效。方法不Foo.act接受任何参数。

package foo

import org.mockito.Matchers.any
import org.mockito.Mockito.{spy, times, verify, when}
import org.scalatest.WordSpec
import org.scalatest.mockito.MockitoSugar

class Foo {
  def act(): Int = {
    (1 to 10).sum
  }
}

class FooSpec extends WordSpec with MockitoSugar {
  "a test" in {
    val spiedFoo = spy(new Foo)
    when(spiedFoo.act()).thenReturn(100)

    val result = spiedFoo.act()

    assert(result == 100)
    verify(spiedFoo, times(1)).act()
  }
}
Run Code Online (Sandbox Code Playgroud)

以下代码中断。方法Foo.act接受 1 个类型的参数Bar。它java.lang.NullPointerException出于某种原因抛出一个

package foo

import org.mockito.Matchers.any
import org.mockito.Mockito.{spy, times, verify, when}
import org.scalatest.WordSpec
import org.scalatest.mockito.MockitoSugar

case class Bar(value: Int)

class Foo {
  def act(bar: Bar): Int = {
    (1 to bar.value).sum
  }
}

class FooSpec extends WordSpec with MockitoSugar {
  "a test" in {
    val spiedFoo = spy(new Foo)
    when(spiedFoo.act(any[Bar])).thenReturn(100)

    val aBar = Bar(10)
    val result = spiedFoo.act(aBar)

    assert(result == 100)
    verify(spiedFoo, times(1)).act(any[Bar])
  }
}
Run Code Online (Sandbox Code Playgroud)

这是从测试中获得的错误消息:

[info] FooSpec:
[info] - a test *** FAILED ***
[info]   java.lang.NullPointerException:
[info]   at foo.Foo.act(FooSpec.scala:12)
[info]   at foo.FooSpec$$anonfun$1.apply$mcI$sp(FooSpec.scala:19)
[info]   at foo.FooSpec$$anonfun$1.apply(FooSpec.scala:17)
[info]   at foo.FooSpec$$anonfun$1.apply(FooSpec.scala:17)
[info]   at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
[info]   at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info]   at org.scalatest.Transformer.apply(Transformer.scala:22)
[info]   at org.scalatest.Transformer.apply(Transformer.scala:20)
[info]   at org.scalatest.WordSpecLike$$anon$1.apply(WordSpecLike.scala:1078)
[info]   at org.scalatest.TestSuite$class.withFixture(TestSuite.scala:196)
[info]   ...
[info] Run completed in 761 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
[info] *** 1 TEST FAILED ***
[error] Failed tests:
[error]         foo.FooSpec
[error] (foo/test:testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 6 s, completed Oct 15, 2019 5:50:20 PM
Run Code Online (Sandbox Code Playgroud)

Mar*_*lic 7

监视真实对象状态的重要问题

有时它是不可能或不切实际的when(Object)用于 stubing 间谍。因此,在使用 spies 时,请考虑 doReturn|Answer|Throw()一系列的 stubbing 方法。

因此尝试

doReturn(100).when(spiedFoo).act(any[Bar])
Run Code Online (Sandbox Code Playgroud)

代替

when(spiedFoo.act(any[Bar])).thenReturn(100)
Run Code Online (Sandbox Code Playgroud)

也考虑转移到mockito-scala,例如

class FooSpec extends WordSpec with Matchers with IdiomaticMockito with ArgumentMatchersSugar {
  "a test" in {
    val spiedFoo = spy(new Foo)
    100 willBe returned by spiedFoo.act(*)

    val aBar = Bar(10)
    val result = spiedFoo.act(aBar)

    result shouldEqual  100
    spiedFoo.act(*) was called
  }
}
Run Code Online (Sandbox Code Playgroud)