hope you all are doing well
I'm facing some problems on testing my Spring Boot application. I created a simple API (currently has only one method, and it's working) and I created the domain tests disabling JPA configurations. When I test with JPA disabled, the tests provide the following error:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.mhrehbein.curriculum.register.infrastructure.mysql.ISpringDataAboutMeRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
When I enable JPA configuration it works fine, but I would like to disable once it is unit tests. You can check the code in the following PR: https://github.com/retatu/curriculum/pull/6/files (sorry for it)
In the code you can see that all tests are broke, the tests are basically the same and the example is here: https://github.com/retatu/curriculum/blob/dev/src/test/java/com/mhrehbein/curriculum/register/domain/entity/AboutMeTest.java
Appreciate any help
In your code you declared an interface that extends PagingAndSortingRepository:
public interface ISpringDataAboutMeRepository extends PagingAndSortingRepository<AboutMe, UUID> {
}
It means that spring boot must autoconfigure this repository bean for you, namely, it will be configured a proxy bean of SimpleJpaRepository.
But since you disabled DataSourceAutoConfiguration in application-test.properties, no DataSource bean is configured, therefore the automatic JpaRepositoriesAutoConfiguration is not activated and user-defined JPA-repositories, in your case ISpringDataAboutMeRepository, are not registered, which leads to the NoSuchBeanDefinitionException. More info about it here.
Also, if you disable HibernateJpaAutoConfiguration, EntityManagerFactory bean isn't configured, which is necessary to create your ISpringDataAboutMeRepository bean.
As a result, if you want to run #SpringBootTest, you need to remove your spring.autoconfigure.exclude property from application-test.properties and configure a database for tests, e.g. in-memory H2-database:
Add to your build.gradle:
testImplementation group: 'com.h2database', name: 'h2', version: '1.4.200'
Your application-test.properties:
spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa
Otherwise, you can use #MockBean annotation on your test classes to mock your ISpringDataAboutMeRepository so:
#SpringBootTest
#ExtendWith(SpringExtension.class) // remove it since #SpringBootTest already contains it
#TestPropertySource(locations = "classpath:application-test.properties")
#MockBean(ISpringDataAboutMeRepository.class)
public class AboutMeTest {
...
}
Spring has it's spring application context which is working as a container of beans. The BeanFactory represents spring's inversion of control container. What it does is exposing beans to the application. When your application requires a bean which is not available then it throws NoSuchBeanDefinitionException.
I think your question and the root cause is best answered in the below question. Hope it will five you insights of the problem.
What is a NoSuchBeanDefinitionException and how do I fix it?
Related
I was working on a project on Spring Boot 1.5. It had the following type of configuration class:
#Configurtion
public class Foo{
#Autowired
private DependencyA dependencyA;
#Bean
public DependencyA getDependency(){
return new DependencyAImpl();
}
}
This worked okay in Spring Boot 1.5, but when I upgraded to Spring Boot 2, this no longer worked, the application would not start up with the exception 'No bean of type DependencyA found'. I figured that this might be because the bean wasn't created when Spring tried to inject the dependency, and so, as a 'hack', added #Lazy to the dependencyA injection. This worked.
In light of this, what is the order of execution of a configuration class. Is it:
A) First create beans and then inject dependencies
B) Try to create instance with all dependencies, and then create any beans in configuration.
Interesting finding;
A configuration class is also a Spring Bean.
Normally Configuration class gets scanned and instantiated first. This has to be the starting point to know about other configurations and beans.
However you have added #Autowire to do Field Injection. As I said, a configuration class is a Spring Bean too. Hence spring needs to resolve its dependencies first. And got into dead lock.
To answer your question.
Configuration Class gets Instantiated First, before other Beans.
I have a large spring applications using annotations that works fine in spring 4.3.13, and am looking to update to spring 5. I am getting all kinds of failures wiring beans, which look like the typical:
Unsatisfied dependency expressed through field 'pcoDAO'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.acme.dao.impl.contracts.PotentialChangeOrderDAO' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
turning on spring debug logging, only nets this additional line
Failed to meta-introspect annotation interface org.springframework.beans.factory.annotation.Autowired: java.lang.NullPointerException
It's not like all #Autowired fields fail, just this one (so far). The bean is specified by an interface, and the implementation is in a sub package of the interface, but again this worked before. The interface's package is specified directly in the
context:component-scan
base-package="com.acme.package.of.interface"
Again this works fine in 4.3.13, and the only change is spring being upgraded to 5.0.5-RELEASE.
Are they any known changes to how spring finds beans? or any documentation about this?
Seems a bug of Spring 5.0.5, and has been fixed in 5.0.6, see this Null check needed in AnnotationUtils.getAnnotation
Please checkout the implementations of respect interface, If it is not there provide implementation.
If implementation is there please check whether they have class level annotation as #Component or any specific annotations.
For info related auto wiring read this.
We are developing a Spring-Boot application which uses ArangoDB with the Spring-Data integration of the ArangoDB team itself (https://github.com/arangodb/spring-data).
We ran into some weird problem when we tried to develop integration tests: when we used #MockBean annotations in test classes for unrelated Spring components, the application context could not be created:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'repository': Unsatisfied dependency
expressed through constructor parameter 1: Ambiguous argument values for
parameter of type [com.arangodb.springframework.core.ArangoOperations] -
did you specify the correct bean references as arguments?
It seems that the mere presence of the #MockBean Annotation produces this error.
Also, Eclipse with installed Spring Tools shows the following error on the Main class:
No constructor with 1 argument defined in class
'com.arangodb.springframework.repository.ArangoRepositoryFactoryBean'
This error message seems to be true as there only is a two-argument constructor for this factory. The tests without #MockBean do run successfully, regardless.
Example
We stripped out project down to a minimal example which you can find on GitHub: https://github.com/mark--/arango-mockbean-error
The relevant code is in the single test class DAOTest. If the #MockBean annotation is present the error from above occurs, if it is removed the application context is created.
Beware: We removed the test setup code in the example project, in particular the setup of an ArangoDB instance with docker: as a consequence the test fails also without the #MockBean annotation but only due to the missing ArangoDB.
Update:
The workaround from MockBean annotation in Spring Boot test causes NoUniqueBeanDefinitionException (give the #MockBean a name) works for us, too, so this seems to be some Spring bug.
The Arango team fixed this problem, see https://github.com/arangodb/spring-data/issues/14#issuecomment-374141173
I am using a spring boot 1.5.4 project where I need a clarification on testing package.
I am seeing Spring Boot comes with #MockBean which is part of org.springframework.boot.test.mock.mockito package.
My question is - Is it similar to Mockito external dependency and I can avoid using Mockito as external dependency as spring boot mock.* package has all features which Mockito has?
As already pointed in Greg's answer , mockito core is already included in spring-boot-starter-test so its already there in your project, no external dependency is needed.
Having said that - mockito's #Mock and Spring's #MockBean are a bit different in a way that #MockBean is basically a #Mock plus #Bean so it does what mockito annotation does plus it works with like a bean too i.e. it places instances in Spring's application context and all other spring bean related concepts come into picture too.
From documentation -
Annotation that can be used to add mocks to a Spring
ApplicationContext. Can be used as a class level annotation or on
fields in either #Configuration classes, or test classes that are
#RunWith the SpringRunner.
Mocks can be registered by type or by bean name. Any existing single
bean of the same type defined in the context will be replaced by the
mock, if no existing bean is defined a new one will be added.
When #MockBean is used on a field, as well as being registered in the
application context, the mock will also be injected into the field.
For non - Spring applications where DI & context are not there, you shoudl use #Mock and for Spring apps , you should use #MockBean.
If you look at the dependencies for spring-boot-starter-test, you'll see that it depends on the Mockito library so it is included for you.
I am working on a Spring boot application that uses Spring JPA with PostgreSQL. I am using #SpringBootTest(classes = <my package>.Application.class) to initialize my unit test for a controller class.
The problem is that this is causing the entityManagerFactory bean (and many other objects related to jpa, datasource, jdbc, etc.) to be created which is not needed for unit tests. Is there a way to prevent Spring from automatically creating these objects till they are actually used the first time?
I spent a lot of time trying to load up only the beans I need for my unit test but ran into many errors. I am relatively new to Spring and I am hoping someone else has run into this before...and can help. I can post code snippets if needed.
Update: I am not sure if I should edit or answer my own question...choosing to edit since I ended up changing my approach to unit tests. I added this to my test config class.
#Configuration
#ComponentScan(basePackages = {"api.controller", "api.config", "api.utils"})
public class TestControllerConfig {
}
and I mocked out the service and repository classes.
You can disable auto configuration in spring-boot using exclude attribute of #EnableAutoConfiguration, as follows:
#Configuration
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class TestConfig {
}
From #EnableAutoConfiguration documentation:
If the class is not on the classpath, you can use the excludeName attribute of the annotation and specify the fully qualified name instead. Finally, you can also control the list of auto-configuration classes to exclude via the spring.autoconfigure.exclude property.