Использование Mockito для шпионажа метода с аргументом объекта приводит к NullPointerException - PullRequest
1 голос
/ 15 октября 2019

Я пытаюсь протестировать некоторый код, используя Mockito.spy, чтобы обеспечить поведение некоторых функций, которые мне нужно предоставить. Хотя я понимаю, что могут быть лучшие альтернативы тому, что я делаю, мне любопытно, почему следующий код выдает NullPointerException в Scala и как его можно решить.

Класс Foo тестируется,Он содержит единственный метод act, который для целей этого вопроса просто вычисляет сумму чисел. Класс FooSpec является соответствующим модульным тестом для класса Foo. Класс Bar - это другой класс, который используется в качестве аргумента для класса 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()
  }
}

Следующий код breaks . Метод 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])
  }
}

Вот сообщение об ошибке, полученное в результате теста:

[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

1 Ответ

3 голосов
/ 15 октября 2019

Важное замечание о шпионаже реальных объектов состояния

Иногда невозможно использовать when(Object) для шпионов-шпионов. Поэтому при использовании шпионов, пожалуйста, рассмотрите doReturn|Answer|Throw() семейство методов окурков.

Поэтому попробуйте

doReturn(100).when(spiedFoo).act(any[Bar])

вместо

when(spiedFoo.act(any[Bar])).thenReturn(100)

Также рассмотрите возможность перехода к 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
  }
}
...