#Profile in #Configuration --> Failed to load ApplicationContext - java

I have 2 configurations in one Spring Batch application, each of them is annotated with #Profile
#Configuration
#Profile("jobA")
public class JobA {
...
...
#Bean
public Job job(Step stepForA) {
...
}
}
#Configuration
#Profile("jobB")
public class JobB {
...
...
#Bean
public Job job(Step stepForB) {
...
}
}
I have a test to run JobB
#RunWith(SpringRunner.class)
#SpringBootTest(classes = { TestJobB.Context.class, JobB.class, JdbcTemplateAutoConfiguration.class, DataSourceAutoConfiguration.class })
#ActiveProfiles("testB")
#TestExecutionListeners(listeners = { DependencyInjectionTestExecutionListener.class })
public class TestJobB extends AbstractTestJob {
...
}
Running the test gives me the error:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'jobLauncherTestUtils': Unsatisfied dependency expressed through method 'setJob' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.batch.core.Job' available: expected at least 1 bean which qualifies as autowire candidate.
The weird thing is, if I dont use #Profile in the 2 Configurations, everything is fine. Any annotation I am missing here?
Thanks, Hadi

Double check your profile names. According to your example, the two configurations are annotated with #Profile("jobA") and #Profile("jobB") respectively. However in your test, you have defined the profile as #ActiveProfiles("testB").
As you noticed, removal of the #Profile annotation in the two configurations they will always be enabled if they are imported correctly. Consequently, the test will use JobB since it declared in the #SpringBootTest annotation.

Related

How to load ServerHttpSecurity in #SpringBootTest?

I want to create a #SpringBootTest that makes use of my full configuration structure.
Problem: I'm creating an #Bean SecurityWebFilterChain that requires a ServerHttpSecurity, which is somehow missing in a test:
#SpringBootApplication
public class MainApp { ... }
//for simple testing I started with anonymous auth
#Configuration
public class ReactiveSecurityConfiguration {
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
return http.anonymous()
.and().csrf().disable()
.build();
}
}
#SpringBootTest
public class TestClass {
#Test
public void test() {
}
}
Result:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'securityWebFilterChain' defined in class path resource [ReactiveSecurityConfiguration.class]:
Unsatisfied dependency expressed through method 'securityWebFilterChain' parameter 0;
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.security.config.web.server.ServerHttpSecurity' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Update
I discovered if I add the following annotations to my Test Class, the testmethod works without errors. But is that intentional?
#EnableWebFlux
#EnableWebFluxSecurity
#SpringBootTest
public class TestClass { }
I'm not certain how your project is arranged, but no, it's not intentional. You can take a look at Spring Security's Reactive Sample that demonstrates this.
It may be that your TestClass is not finding the #SpringBootConfiguration annotation attached to MainApp.
I have a spring-boot-starter-web dependency pulled somewhere in the classpath. Removing it resolved the problem.
If both web and webflux dependency should be kept, it's still possible to run a test in reactive only, with:
#SpringBootTest(properties = "spring.main.web-application-type=REACTIVE")
class MyWebFluxTests {
// ...
}

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);
}
}

Spring Boot/JUnit - No qualifying bean of type 'boolean' available

I have been using Spring for a number of months now, but still do not understand some of the various subtleties imposed by the framework.
I am trying to execute a unit test for a class and am running into the often seen error message and exception:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 1 of constructor in <package>.MessagingManager required a bean of type 'boolean' that could not be found.
Action:
Consider defining a bean of type 'boolean' in your configuration.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'boolean' available: expected at least 1 bean which qualifies as autowire candidate.
The unit test class (messagingManager is the SUT):
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = {MessagingManager.class})
public class TestMessagingManager {
#Autowired
private MessagingManager messagingManager;
...
A configuration class:
#Configuration
#EnableScheduling
#EnableAsync
#ComponentScan({"<package 1>"})
public class ServiceConfigurer {
...
#Value("${service.name}")
private String serviceName;
...
#Bean(name = "messagingManager")
public MessagingManager messagingManager() {
return new MessagingManager(serviceConfig(), "MISSION_PLANNER".equals(serviceName));
}
...
#Bean
public ServiceConfig serviceConfig() {
return config.getServiceByName(serviceName);
}
...
}
The SUT class:
public class MessagingManager {
...
public MessagingManager(ServiceConfig serviceCfg, boolean transactional) {
...
}
...
}
I tried using org.springframework.test.util.ReflectionTestUtils.setField() to set the serviceName field in the ServiceConfigurer class, but that did not help. I suspect it doesn't work because the problem is occurring when DI is involved and that the reflection utility usage is "too late". Just a guess.
What am I doing wrong?
If I were to entertain the idea of "creating a bean of type boolean", how do I define a bean that simply holds a boolean value, that's set based on the value of another configured piece of information? Are there alternatives?
With
#SpringBootTest(classes = { MessagingManager.class })
Spring tries to add a bean of type MessagingManager to your context. It does so by invoking the only available constructor. Spring now want to inject beans of type ServiceConfig and boolean as constructor parameters. But this fails because there is no bean of type boolean in the test context.
One solution would be to change this line to
#SpringBootTest(classes = { ServiceConfigurer.class })
because ServiceConfigurer knows how to construct a bean of type MessagingManager.
To inject properties to your test you can add
#TestPropertySource(properties = { "service.name=example" })
to your test class.

No qualifying bean of type 'springfox.documentation.schema.TypeNameExtractor'

I'm trying to implement Swagger using the JHipster implementation as reference into my Kotlin application.
However, when I run my tests, I get the following error for most of my tests (these tests work fine if I remove this swagger code):
Caused by:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'pageableParameterBuilderPlugin' defined in class path resource [com/application/config/apidoc/SwaggerPluginsAutoConfiguration$SpringPagePluginConfiguration.class]: Unsatisfied dependency expressed through method 'pageableParameterBuilderPlugin' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'springfox.documentation.schema.TypeNameExtractor' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
My SwaggerPluginsAutoConfiguration class:
#Configuration
#ConditionalOnWebApplication
#ConditionalOnBean(Docket::class)
#AutoConfigureAfter(SwaggerAutoConfiguration::class)
class SwaggerPluginsAutoConfiguration {
#Configuration
#ConditionalOnClass(Pageable::class)
class SpringPagePluginConfiguration {
#Bean
#ConditionalOnMissingBean
fun pageableParameterBuilderPlugin(typeNameExtractor: TypeNameExtractor,
typeResolver: TypeResolver): PageableParameterBuilderPlugin {
return PageableParameterBuilderPlugin(typeNameExtractor, typeResolver)
}
}
}
The SwaggerAutoConfiguration class:
#Configuration
#ConditionalOnWebApplication
#ConditionalOnClass(ApiInfo::class, BeanValidatorPluginsConfiguration::class, Servlet::class, DispatcherServlet::class)
#Profile(value = [SPRING_PROFILE_SWAGGER])
#EnableSwagger2
#Import(BeanValidatorPluginsConfiguration::class)
class SwaggerAutoConfiguration(applicationProperties: ApplicationProperties) {
...
}
If I include the swagger profile in my tests application config file, the tests pass. However, if the profile isn't present, the tests fail with the error above. I'm not sure why Spring is trying to configure swagger if the profile isn't set.
How can I set this up, so that the configuration doesn't try to load if the profile isn't specified?

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