stubbing two methods in a mock is throwing Exception using Mockito and Spring MockMVC

允我心安 提交于 2019-12-12 19:24:00

问题


I am trying to set up some simple MVC Unit Testing. What I am trying to accomplish is this:

  • Use Spring MockMVC to test HTTP status and HTTP data returned from my controllers.
  • My controllers have an Autowired reference to a facade which performs the actual logic.
  • So, I create one Test class to test one controller.
  • I want to test two methods of that controller, so I created two methods in my Test class.
  • I've mocked my facade and inject it in my controller.
  • So, I want to configure this mock with the return of each of the methods I am testing.

I am using the following code:

public class LoginTest {

    MockMvc mockMvc;

    @Mock
    Cadastre facade;

    @InjectMocks
    Login controller;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        Mockito.when(facade.login(Mockito.any(String.class))).thenReturn(true);
        Mockito.when(facade.getUser(Mockito.any(String.class))).thenReturn(Mockito.any(UserData.class));

        mockMvc = MockMvcBuilders.standaloneSetup(controller).setMessageConverters(new MappingJackson2HttpMessageConverter()).build();
    }

    @Test
    public void thatLoginUsesStatusOK() throws Exception {
        this.mockMvc.perform(MockMvcRequestBuilders.get(UserFixtures.loginUrl())).andExpect(MockMvcResultMatchers.status().isOk());
    }

    @Test
    public void thatUserDataUsesStatusOK() throws Exception {
        this.mockMvc.perform(MockMvcRequestBuilders.get(UserFixtures.getUserDataUrl())).andExpect(MockMvcResultMatchers.status().isOk());
    }
}

If I try to execute this Test class, it fails with the error:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
1 matchers expected, 2 recorded:
-> at com.example.test.api.login.LoginTest.setup(LoginTest.java:38)
-> at com.example.test.api.login.LoginTest.setup(LoginTest.java:39)

This exception may occur if matchers are combined with raw values:
    //incorrect:
    someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
    //correct:
    someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.

    at com.example.test.api.login.LoginTest.setup(LoginTest.java:39)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

If I move each mocked method line (the Mock.when lines) inside its test() method, and call this test methods separately, they work. But if I try to execute the whole class, then only one of the test() methods work, and the other throws the following exception (which seems to have the same cause as above to me):

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced argument matcher detected here:

-> at com.example.test.api.login.LoginTest.thatLoginUsesStatusOK(LoginTest.java:45)

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
    verify(mock).someMethod(contains("foo"))

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().

    at com.example.test.api.login.LoginTest.setup(LoginTest.java:37)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

So, I believe the cause is that I probably did not understand very well how to use Mockito. Could you please point me in the right direction?

Thanks a lot!


回答1:


Your problem is where you write

thenReturn(Mockito.any(UserData.class))

The any method is for matching values that come up during your test, not for creating values. You need to specify what UserData object to return, presumably by instantiating one and passing it in here.



来源:https://stackoverflow.com/questions/21532988/stubbing-two-methods-in-a-mock-is-throwing-exception-using-mockito-and-spring-mo

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