#Component not being read in Spring test - java

I created an Integration test to test the new feature I just added but the Spring wiring is not working. The unit tests all work and the existing Spring integration tests still work but I am unable to Autowire my new class
Here is the error message –
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.xxx.xxx.etc.MyNewClassTest’: Unsatisfied dependency expressed through field 'sut'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.xxx.xxx.etc.MyNewClass ' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
The new class –
#Slf4j
#Component
public class MyNewClass extends AbstractRetryJob<Event> {
My test -
#ExtendWith(SpringExtension.class)
class MyNewClassTest {
#Autowired private MyNewClass sut;
Any idea on what is going wrong?

Adding #ExtendWith(SpringExtension.class) is not enough to create the Spring context. You need to add #SpringBootTest to your MyNewClassTest. Per the appropriate comment, you can drop #ExtendWith(SpringExtension.class)
#SpringBootTest
class MyNewClassTest {
#Autowired private MyNewClass sut;
}

Related

How to add a protected configuration with access to properties to a Spring Boot Test context?

i use JUnit 5 with Spring Boot 2.5.2 . Now i want to write a Unit test, that does not load the full Application context.
Therefore i annotate my test like that:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {ConfigurationA.class})
class Test1{
...
}
In ConfigurationA the Bean1 gets created.
The Problem is that the ConfigurationA accesses an ConfigurationB for creating Bean1, but ConfigurationB is protected.
Now i get the following Error:
Error creating bean with name 'Bean1' defined in com.package.sample.config.ConfigurationA: Unsatisfied dependency expressed through method 'createBean1' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.package.sample.config.ConfigurationB available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
When i change #ContextConfiguration... to #SpringBootTest it works but the whole Context gets loaded.
Is there any solution to load not the whole context?
Just make ConfigurationA extend ConfigurationB

Exclude EurekaClient Bean from Application Context in SpringBootApplicationTest

I'm trying to write a integration test against my Spring Data API with the following test configuration.
eureka:
client:
enabled: false
[..] # No other configuration part that affects discovery/eureka client
This is my test class
#SpringBootTest
#AutoConfigureMockMvc(addFilters = false)
#Transactional
class FooAPITest {
#Test
void contextLoads() {
}
}
However I have a component which injects the EurekaClient to get a service instance from it
#Component
public class ServiceClient {
#Autowired
public ServiceClient(#Qualifier("eurekaClient") EurekaClient eurekaClient) {
URI serviceUri = URI.create(eurekaClient.getNextServerFromEureka("service", false).getHomePageUrl());
}
}
So as of this service my application is not able to load the ApplicationContext.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.netflix.discovery.EurekaClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Qualifier(value="eurekaClient")}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:885)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:789)
... 81 more
What I've tried so far
I thought about setting up a custom ContextConfiguration to exclude the ServiceClient as it is not needed in the test class. However I need to include a Configuration File which autowires the EntityManager but when I use #SpringBootApplication(classes = {Configuration.class}) the EntityManager can not be injected. This Configuration looks like that:
#Configuration
class Configuration {
#Autowired
EntityManager entityManager;
}
This produces the same error but with EntityManager Bean:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
... 81 more
Current Workaround
Currently I'm avoiding the problem by mocking the ServiceClient but I want to get rid of that code smell.
#MockBean
ServiceClient serviceClient;
#BeforeEach
void setUp() {
MockitoAnnotations.initMocks(FooAPITest.class);
}
Another workaround would be to mark the Injected Beans as not required but I don't find that practicable only to make the tests work.
What is a proper way to solve this problem?
You can try mocking the EurekaClient in your test:
#SpringBootTest
#AutoConfigureMockMvc(addFilters = false)
#Transactional
class FooAPITest {
#MockBean
private EurekaClient eurekaClient;
#Test
void contextLoads() {
}
}
This will create the EurekaClient as a mocked bean in the ApplicationContext to be injected into your service.
If you have other tests that initialize the Spring ApplicationContext, you can create a separate configuration class within the application package to be scanned (using #ConditionalOnMissingBean annotation to cover all bases):
#Configuration
public class MockEurekaConfiguration {
#Bean
#ConditionalOnMissingBean
public EurekaClient eurekaClient() {
return Mockito.mock(EurekaClient.class);
}
}

#autowire not creating object with custom annotation in junit

I am new to spring boot and I am writing Junit for my REST Api.so many annotation are required by my class to run Junit. So I planned to put all annotation in one custom annotation and use that custom annotation in my Junit class. But now my Autowire is stopped working.
I tried to create custom annotation and used that in my Junit class
but now #Autowire annotation has stopped to work.
Below is code of custom annotation:
#Inherited
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.CLASS)
#Documented
#Category(UnitTest.class)
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = {AptDataApiApplicationRepo.class })
#TestPropertySource("classpath:application-test.properties")
public #interface RepoTestConfig {
}
// My JUnit class code
#RepoTestConfig
public class HolidayRepoTest {
#Autowired
private IHolidayRepo iHolidayRepo;
}
// here spring throwing an exception when spring context is trying to get up
Exception coming is :
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.demo.repository.IHolidayRepo' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
#Note: When I am putting all annotation in HolidayRepoTest class then every thing is fine.

SpringBoot and JUnit - Testing Service class - Failed to load Application Context

I'm trying to run a unit test on a service class in a Spring Boot Application
i would like to try this test
#RunWith(SpringRunner.class)
#SpringBootTest(classes=Application.class) //my #SpringBootApplication class
public class UserServiceTest { //i'm testing my UserService implementation
#TestConfiguration
static class UserServiceContextConfiguration {
#Bean
public IUserService service() {
return new UserService();
}
}
#Autowired
private IUserService service;
#MockBean
private UserRepository repository;
#Before
public void setUp() {
User me = new User();
me.setEmail("admin#admin.com");
Mockito.when(repository.findByEmail(me.getEmail())).thenReturn(me);
}
#Test
public void whenValidEmail_thenFindUser() {
String email = "admin#admin.com";
User found = service.findByEmail(email);
assertThat(found.getEmail()).isEqualTo(email);
}
}
But when launching the test i get this exception
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.myapp.service.UserServiceTest': Unsatisfied dependency expressed through field 'service'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.myapp.service.interfaces.IUserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Maybe it is not clear to me but #TestConfiguration should allow me to define my beans from the application to use them in the tests and #SpringBootTest should load all the application context from the app for the test environment...
By providing classes=Application.class you turned off automatic scanning of inner configuration classes.
Either remove the explicit classes parameter - SpringRunner will search for SpringBootApplication annotated class in current packages and parent packages and also search for inner configuration classes,
or add this to your #SpringBootTest
#SpringBootTest(classes= {Application.class, UserServiceContextConfiguration.class })

SpringBootTest for DAO JUnit test

I am attempting the following unit test of a DAO.
I am unable to get the DataSource recognized.
Can I get a tip on how to resolve this?
Details below
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class EntityDaoTest {
#Autowired
protected EntityDao entityDao;
#Before
public void setup()
{
}
#Test
public void test() throws InternalServerException
{
List<Entity> entities = entityDao.list();
assert(entities.size()==0);
}
}
The relevant aspects of the DAO class are as follows
#Repository
public class EntityDao extends GenericDao<Entity>{
public EntityDao(DataSource dataSource) {/.../}
}
My src/test/resources/application.properties file is as follows
# Database
spring.datasource.url=jdbc:mysql://localhost:3306/db
spring.datasource.username=dbuser
spring.datasource.password=dbpass
Trace from running as JUnit test in Eclipse
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityController': Unsatisfied dependency expressed through field 'entityDao': Error creating bean with name 'entityDao' defined in file .../target/classes/hitstpa/dao/EntityDao.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type [javax.sql.DataSource] found for dependency [javax.sql.DataSource]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {};
...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'entityDao' defined in file [/home/fmason/workspace/hitstpa/target/classes/hitstpa/dao/EntityDao.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type [javax.sql.DataSource] found for dependency [javax.sql.DataSource]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] found for dependency [javax.sql.DataSource]: expected at least 1 bean which qualifies as autowire candidate for this dependency. ...`
Application structure
-src
--main
---java
----Application.java
----com
----hitstpa
-----controller
-----dao
------EntityDao.java
-----model
---resources
----application.properties
--test
---java
----hitstpa
-----dao
------EntityDaoTestDOTjava
---resources
----applicationDOTproperties
First of all for integration tests you need an integration Db with some fixed data.
Now you need to create a configuration class which will create the
integration test specific dependencies(I have named it as DbConfig
.java)
Next is add #ContextConfiguration annotation to the integration test
class and provide DbConfig.java, so that when test runs it will
create the datasource dependency and inject it to the container
Sample Code
#Configuration
public class DbConfig {
#Bean
public DataSource dataSource() {
//Create the DataSource with integration-DB properties
return dataSource;
}
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
#ContextConfiguration(classes=DbConfig.class)
public class EntityDaoTest {
}
For the record, I believe this is not a good unit test. This test requires that a mysql databases exists on localhost.
Anyhow, the errors suggest that the Spring Context isn't loaded correctly. When using SpringBootTest, Spring looks for the configuration using the test's package as root. So, if it's lower than your Configuration classes, it won't them.
Take a look at Spring's documentation:
The search algorithm works up from the package that contains the test
until it finds a #SpringBootApplication or #SpringBootConfiguration
annotated class. As long as you’ve structure your code in a sensible
way your main configuration is usually found.
Solution:
You can either move your tests to the same level as your SpringBoot Main class or change it to: #SpringBootTest(classes = YourSpringBootMainClass.class)

Categories