org.mockito.exceptions.misusing.MissingMethodInvocationException in MOCKITO

删除回忆录丶 提交于 2021-02-07 18:22:18

问题


I am having a simple controller class

@RestController
open class MyController() {

@Autowired
lateinit var myInterface: MyInterface

@GetMapping(value = ["/v1/call-Api"], produces = ["application/json"])
fun getData():Response{
   callFx()
   /// Here I have logic
 }

  fun callFx():String{
    return myInterface.getmyStringData()
  }
}

Now Come to implementation part of

MyInterface

@Service
class MyImpl: MyInterface {
  override fun getmyStringData(){
        return "Some string"
    }
}

Please note that for MyInterface, I have only one implementation class.

Now come to Test case of controller class

class ControllerTest{

@Autowired
lateinit var myIntF: Myinterface


@Test
fun controllerTest(){         
Mockito.`when`(myIntF.getmyStringData()).thenReturn("Some mock string")
// Some code over here
}

}

After all these I am keep getting below error

  org.mockito.exceptions.misusing.MissingMethodInvocationException: 
  when() requires an argument which has to be 'a method call on a mock'.
  For example:
  when(mock.getArticles()).thenReturn(articles);

  Also, this error might show up because:
  1. you stub either of: final/private/equals()/hashCode() methods.
  Those methods *cannot* be stubbed/verified.
  Mocking methods declared on non-public parent classes is not supported.
  2. inside when() you don't call method on mock but on some other object.

Even though code syntax belongs to Kotlin but i keep it simple to elaborate me scenario. Any JAVA guy can also help me.

Any help would be really helpful for me.


回答1:


The problem:

Below is your test class

class ControllerTest{

@Autowired
lateinit var myIntF: MyInterface


@Test
fun controllerTest(){         
Mockito.`when`(myIntF.getmyStringData()).thenReturn("Some mock string")
// Some code over here
}

Since you have used @Autowired, the real implementation is used and not the mock object and hence when you do Mockito.when(myIntF.getmyStringData()).thenReturn("Some mock string") , you get the error when() requires an argument which has to be 'a method call on a mock'. This is because myIntF is not a mock object.

The solution:

First, since it's a controller test, you need to have the controller field annotated with @InjectMocks to inject the mocked MyInterface obj into it. Then you need to annotate the MyInterface field with @Mock which would create a mocked object. Then you need to have a @Before or @BeforeEach method with MockitoAnnotations.initMocks(this) to initialize objects annotated with Mockito annotations. Only after that, the method call mocking with Mockito.when(mockedObject.methodCall).thenReturn(mockedValue) would work.

class ControllerTest{

@InjectMocks
lateinit var controller: MyController

@Mock
lateinit var myIntF: MyInterface

@BeforeEach
fun init() {
    MockitoAnnotations.initMocks(this)
}


@Test
fun controllerTest(){         
    Mockito.`when`(myIntF.getmyStringData()).thenReturn("Some mock string")
    // Some code over here
    controller.callFx() //this would return "Some mock string"
}



回答2:


I'm not familiar with @Autowire so this might be a completely wrong assumption, but it's also too big for a comment, so here it goes.

The exception basically explains that the object you're trying to mock isn't a mock and from what I can see, this is true.

Usually one can do something like:

@Mock
lateinit var myIntF: Myinterface

@Before
fun setUp() {
  MockitoAnnotations.initMocks(this)
}

And now the mock is created and you can configure it with when like you have.

There are other options to initialize this, such as running the test with the mockito test runner. I believe there's also a test rule and you'll always have mockito-kotlin which is great for kotlin code and it's much simpler in my personal opinion:

lateinit var myIntF = mock<Myinterface>()

@Test
fun controllerTest(){ 
  myIntF.stub {
   on { getmyStringData() } doReturn "Some mock string"
  }
}

The point here is that I think you didn't actually create a mock and mockito needs this because if I'm not mistaken it works by inheriting from the class it's mocking.

Edit:

As pointed out in the comments you might want to test the controller. This means you'll need to instantiate it with the mocks you've created. One suggested way is to use @InjectMocks. Something like:

@InjectMocks
lateinit var controller: MyController

But without knowing the whole test code it's hard to say this is exactly what you want.



来源:https://stackoverflow.com/questions/60950079/org-mockito-exceptions-misusing-missingmethodinvocationexception-in-mockito

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!