【问题标题】:How can I use the Mock annotation in Scala?如何在 Scala 中使用 Mock 注释?
【发布时间】:2021-11-20 20:32:07
【问题描述】:

我正在使用 scalatest 和 Scala 2.x。以下编译/工作:

import org.mockito.Mockito._
import org.mockito._
import org.mockito.ArgumentMatchers._

class Test1 extends AnyFunSuite { 

  val action = Mockito.mock(classOf[Action])
  when(action.process(anyInt())).thenReturn("x")
  ...
}

这不是:

import org.mockito.Mockito._
import org.mockito._
import org.mockito.ArgumentMatchers._

class Test1 extends AnyFunSuite { 

  @Mock
  val action = Action()
  when(action.process(anyInt())).thenReturn("x")
  ...
}

我在“何时”行收到此异常:

[info] Test1 *** ABORTED ***
[info]   org.mockito.exceptions.misusing.InvalidUseOfMatchersException: Misplaced or misused argument matcher detected here:
[info]
[info] -> at Test1.<init>(Test1.scala:17)
[info]
[info] You cannot use argument matchers outside of verification or stubbing.
[info] Examples of correct usage of argument matchers:
[info]     when(mock.get(anyInt())).thenReturn(null);
[info]     doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
[info]     verify(mock).someMethod(contains("foo"))
[info]
[info] This message may appear after an NullPointerException if the last matcher is returning an object
[info] like any() but the stubbed method signature expect a primitive argument, in this case,
[info] use primitive alternatives.
[info]     when(mock.get(any())); // bad use, will raise NPE
[info]     when(mock.get(anyInt())); // correct usage use
[info]
[info] Also, this error might show up because you use argument matchers with methods that cannot be mocked.
[info] Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
[info] Mocking methods declared on non-public parent classes is not supported.
[info]   at Test1.<init>(Test1.scala:17)
[info]   at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
[info]   at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
[info]   at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
[info]   at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
[info]   at java.lang.Class.newInstance(Class.java:442)
[info]   at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:450)
[info]   at sbt.TestRunner.runTest$1(TestFramework.scala:140)
[info]   at sbt.TestRunner.run(TestFramework.scala:155)
[info]   at sbt.TestFramework$$anon$3$$anonfun$$lessinit$greater$1.$anonfun$apply$1(TestFramework.scala:318)
[info]   ...

【问题讨论】:

    标签: scala mockito


    【解决方案1】:

    就我个人而言,我会完全避免嘲笑,但如果你真的需要它,在 Scala 中我会使用类似 ScalaMock 的东西,它与语言更好地配合。

    class Test1 extends AnyFunSuite { 
    
      val action = mock[Action]
      (action.process _).expects(*).returning("x")
      ...
    }
    

    据我所见,@Mock 注释依赖于一些 custom JUnit runner,它通过将类似 Guice/Spring 的依赖注入与模拟相结合将逻辑注入测试类。但是你用错了:

    // Here you would have to configure JUnit runner
    // (but Scala test libraries are not really JUnit-based)
    class Test1 extends AnyFunSuite { 
    
      // Here you would have to configure action as var
      // and not initialize it yourself, so that runner could
      // create the mocks and put them here using reflection
      // after instance initialization
      @Mock
      var action: Action = _
    
      // Here you could not have the test logic be implemented
      // as vals or vars, because it would be executed in object's
      // constructor - when action is still unititialized
      // (therefore null). JUnit doesn't show this issue as it
      // uses @Mock on class attributes, and put @Test logic in
      // methods - called only after constructor is completed
      // and JUnitRunner injects additional logic 
      // ...
    }
    

    你完全可以这样做:

    // use JUnit instead of Scalatest
    @RunWith(classOf[MockitoJUnitRunner])
    class Test1 {
    
      @Mock
      var action: Action = _
    
      @Test
      def example(): Unit = {
        // ...
      }
    }
    

    所以 可以让它在 Scala 中工作,只是不能使用非基于 JUnit 的测试库。如果您对 ScalaTest 中的 Mockito 约定感兴趣,请参阅a dedicated documentation page。

    【讨论】:

    • 我建议使用来自 mockito 项目的 scala mockito 而不是 scalatest。与scalatest相比,它支持更多的功能
    猜你喜欢
    • 2011-02-27
    • 2019-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-12
    • 1970-01-01
    相关资源
    最近更新 更多