Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to not use @MockBean on Spring MVC tests?

I'm trying to test the Rest contract of my Rest Controller using @WebMvcTest, like:

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
class MyControllerTest {

The method that I'm testing use only MyFirstService, but inside the class there another two services (MySecondService and MyThirdService) used by two other methods.

The problem is the use of @MockBean. The test class seems, in the final, like this:

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
class MyControllerTest { 

    @MockBean
    private MyFirstService s1; // internal method mocked for the test

    @MockBean
    private MySecondService s2; //never used

    @MockBean
    private MyThirdService s3; //never used

    ...

    @Test
    public void testMethod() [
        // mock s1
        // calls rest controller method
        MvcResult mvcResult = mvc.perform(post("/products")
            .header("Content-Type", "application/json")
            .content(json))
            .andExpect(status().isCreated())
            .andReturn();
    }

}

I think that this solution is not elegant with these annotations... The declared s2 and s3 appears to not be used from who read the code. And every service that is injected in the MyController needs to be there with @MockBean.

So, I have two questions:

  1. Is there a way to not use @MockBean on Spring MVC tests?
  2. Is there a better way to do the same thing, even using @MockBean?
like image 977
Dherik Avatar asked Jan 29 '18 14:01

Dherik


1 Answers

First question :

Is there a way to not use @MockBean on Spring MVC tests?

@WebMvcTest allows to configure only MVC beans in the Spring context.
As advantage, it isolates the tests and makes their execution faster.
As drawback, it requires to provide mocks for dependencies of the tested controllers even if they are not needed in the tested method.

The Spring documentation confirms that :

41.3.7 Auto-configured Spring MVC tests

Often @WebMvcTest will be limited to a single controller and used in combination with @MockBean to provide mock implementations for required collaborators.

So in your case, you don't have the choice.

Second question :

Is there a better way to do the same thing, even using @MockBean?

I think that you can produce a better code by using @MockBean for fields which you want to mock specific things in your test and @MockBeans for other bean classes depending of the controller under test.

No tested but you could try :

@RunWith(SpringRunner.class)
@WebMvcTest(MyController.class)
@MockBeans({ @MockBean(MySecondService.class), 
             @MockBean(MyThirdService.class) 
           }) // technical mocks for the dependencies resolution

class MyControllerTest { 

    @MockBean
    private MyFirstService s1; 

    @Test
    public void testMethod() [
        // mock s1
        // calls rest controller method
        MvcResult mvcResult = mvc.perform(post("/products")
            .header("Content-Type", "application/json")
            .content(json))
            .andExpect(status().isCreated())
            .andReturn();
    }

}
like image 121
davidxxx Avatar answered Nov 13 '22 10:11

davidxxx