I am writing a component using Spring Boot and Spring Boot JPA. I have a setup like this:
The interface:
public interface Something {
// method definitions
}
The implementation:
@Component
public class SomethingImpl implements Something {
// implementation
}
Now, I have a JUnit test which runs with SpringJUnit4ClassRunner
, and I want to test my SomethingImpl
with this.
When I do
@Autowired
private Something _something;
it works, but
@Autowired
private SomethingImpl _something;
causes the test to fail throwing a NoSuchBeanDefinitionException
with the message No qualifying bean of type [com.example.SomethingImpl] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
But in the test case, I want to explicitly inject my SomethingImpl
because it is the class I want to test. How to I achieve this?
The error is “expected at least 1 bean which qualifies as autowire candidate.” The solution is to add the injection class in the ApplicationContext using annotation @Component. The exception “NoSuchBeanDefinitionException: No qualifying bean of type” is resolved if the annotation @Component is added in the Lion class.
if Spring encounters multiple beans with same type it checks field name. if it finds a bean with the name of the target field, it injects that bean into the field.
When a bean implementation exists both in the production and test codes, IntelliJ will mark @Autowired instances of this bean as "cannot autowire, more than one bean...". This is of course incorrect, as the test implementation will never be deployed in a production environment.
The best solution is to properly isolate beans. The DispatcherServlet is responsible for routing and handling requests so all related beans should go into its context. The ContextLoaderListener , which loads the root context, should initialize any beans the rest of your application needs: services, repositories, etc.
If you want a special bean you have to use the @Qualifier
annotation:
@Autowired
@Qualifier("SomethingImpl")
private Something _something;
I figured out you can do the same with a javax.inject
style DI:
@Named("myConcreteThing")
public class SomethingImpl implements Something { ... }
Where you want to inject it:
@Inject
@Named("myConcreteThing")
private Something _something;
This is correctly picked up by @EnableAutoConfiguration
and @ComponentScan
.
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