The following code taken from the doc doesn't work as expected:
@RunWith(SpringRunner.class)
@WebMvcTest(TestController.class)
public class TestControllerTest {
@MockBean
private TestValidator testValidator;
@Autowired
private TestRestTemplate restTemplate;
@Test
public void test() throws Exception {
// no-opts
});
}
... where's the mocked bean is:
@Component
public class TestValidator implements Validator {
@Autowired
private TestRepository testRepository;
...
}
during test startup it fails:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testController': Unsatisfied dependency expressed through field 'testValidator': Error creating bean with name 'com.example.TestValidator#0': Unsatisfied dependency expressed through field 'categoryRepository': No qualifying bean of type [com.example.TestRepository] found for dependency [com.example.TestRepository]: expected at least 1 bean which qualifies as autowire candidate for this dependency.
Java: 1.8.0_65 Spring Boot: 1.4.0.RELEASE & 1.4.1-BUILD-SNAPSHOT Maven: 3.3.3
Comment From: wilkinsona
Thanks for the sample.
I don't think this has anything to do with @MockBean
. The problem is that you're using @WebMvcTest
but with a bean that autowires a Data JPA repository. Data JPA repositories aren't created when using @WebMvcTest
.
Rather than mocking TestValidator
, is there any reason why you can't mock Validator
instead? You'd have to change the injection point in TestController
. Alternatively, you can also avoid the problem by using constructor injection instead of field injection.
I guess we could look at disabling autowiring for beans created using @MockBean
so that if it's a mock created from a class (rather than from an interface) no attempt is made to inject anything into it.
Comment From: WildDev
@wilkinsona ,
I don't think this has anything to do with @MockBean. The problem is that you're using @WebMvcTest but with a bean that autowires a Data JPA repository. Data JPA repositories aren't created when using `@WebMvcTest.
yes, but there is any controller interacts with the database either via service layer or whatever else. In order to test a controller it is necessary to mock its dependencies anyway. Data JPA repository shouldn't be autowired at all since it is just a dependency of the dummy object.
I will try your suggestion but IMAO, the @MockBean
annotation should behave the same like Mockito's @Mock
annotation does - it just makes a dummy object without any nested dependencies resolved.
Comment From: wilkinsona
Will try your suggestion but IMAO, the @MockBean annotation should to behave exactly like Mockito's
@Mock
does
In terms of how the mock is created, that's exactly what @MockBean
does. However, we have to do more than @Mock
– the mock has to be added to the application context so that it can be injected into other components. It's the fact that's it's a bean in the application context that means that an attempt is made to inject its fields which is what's causing the problem you've reported.
Comment From: WildDev
@wilkinsona , then it behaves rather like a stub that not always sufficient for the testing
Comment From: snicoll
Looks like a rephrased clone of #6658
Comment From: WildDev
@snicoll , has nothing with the #6658 at all
Comment From: snicoll
Yeah, @wilkinsona just told me. The complaints look alike :)
Comment From: SingleShot
I experience this same problem when the unit under test's dependencies are plain old Spring beans that themselves have autowired dependencies. If the unit's dependencies are interfaces, no problem, they mock fine. But if classes, the mocking does not work completely and requires the dependencies of the dependency to be wired in.
The "workaround" for this is to provide @MockBean
s for dependencies of the dependency, and dependencies of the dependency's dependencies and so on down, which is pretty ugly. Another is to only use interfaces for your dependencies - which I prefer - but you don't always have that luxury when the dependency is not in your control. Of course, I could wrap it in my own interface but that's extra code that I wouldn't need if @MockBean
behaved like Mockito class mocking from the standpoint of not needing to provide dependencies to the mock.
For me - someone trying to port a legacy (and very messy) Spring app over to several Spring Boot apps - getting this fixed is important. (Oh I see it is no longer waiting for triage - thanks!)
Comment From: snicoll
Fixed in https://github.com/spring-projects/spring-boot/commit/0e00a49dcc246893fcaf1c7a0497fac6dcbc7454
Comment From: StasKolodyuk
I experience the same issue for @SpyBean
. However, the @MockBean
works correctly in 1.4.1.RELEASE
Comment From: wilkinsona
@StasKolodyuk That's to be expected. Unlike a mock, a spy is a wrapper around a "proper" bean. For the bean that's being spied upon to work properly it needs to have its dependencies injected.
Comment From: StasKolodyuk
@wilkinsona That makes sense, thank you!
Comment From: danilobalarini
Just to say that i got rid of this bug by removing the @ComponentScan
from my @SpringBootApplication
-
Application.class
There is no need for it anymore (using spring-boot 1.5.2)
Comment From: stahloss
For my project setup @MockBean
is still not working as it should. We have multiple @Configuration
s that are imported by our @SpringBootApplication
annotated class. These @Configuration
classes each have their own @Import
or @ImportResource
.
When using @MockBean
we get all kinds of wiring issues, but when we mock or stub implement our rest controller manually, things are fine as is our application in general.
I am able to get @MockBean
working, but only when I remove the explicit @Import
s, but of course this breaks everything else.
Comment From: snicoll
@D0rmouse this issue was closed almost 2 years ago. If you have a usage question please ask on StackOverflow with a link to a minimal sample that reproduces the behaviour you're experiencing. The description you shared is vague and we won't be able to help you effectively without more details. If you believe you've found a bug in Spring Boot, please create a separate issue with a link to a minimal sample.
Comment From: stahloss
@snicoll Thanks for your response. I don't need usage help, just giving you a heads-up that @MockBean
has wiring issues in the described situation. Stub implementing our business service interface wired by our rest controller does not have this issue.
I'll see if I can create a minimal setup to reproduce this and create a separate issue.