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:
@MockBean
on Spring MVC tests?@MockBean
?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();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With