#ActiveProfile("integration-test") in SpringBoot test not resolving - spring-boot

I have an integration test with the following configuration:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("integration-test")
#ContextConfiguration(classes = { PersistenceJpaConfig.class, ContextConfig.class, ServiceConfig.class, WebConfig.class})
#WebAppConfiguration
public class LeadsIntegrationTest {
...
}
The PersistenceJpaConfig class is the following:
#Configuration
#EnableTransactionManagement
#ComponentScan({ "org.persistence", "org.common.persistence" })
#PropertySource({ "persistence-${spring.profiles.active}.properties" })
#EnableJpaRepositories(basePackages = org.persistence.dao")
public class PersistenceJpaConfig {
...
}
The ${spring.profiles.active} resolves fine when the active profile is "dev", but when set to "integration-test" in the #ActiveProfiles("integration-test), it fails to resolve. Both the persistence-dev.properties and persistence-integration-test.properties are located in src/main/resources . The properties for dev has mysql configuration, and the integration-test has h2 embedded configuraiton for running integration tests that are isolated from dev data. When the test runs, I get the following:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.profiles.active' in string value "persistence-${spring.profiles.active}.properties"
What is going on here?

You haven't told how you set the dev profile but my best guess is that you set it with a system property. When you use #ActiveProfiles the resolution of the profile comes too late for the #PropertySource annotation to pick up the value.
Regardless, do you know that 100% of that custom code there is supported out of the box with spring boot? Why can't you put that stuff in application-integration-test.properties and application-dev.properties?

Related

Define Spring profile groups programatically / use then in #ContextConfiguration tests

I'd like to use Spring profile groups in fast ContextConfiguration unit tests.
Given the following application.yaml definition in test scope and profile configuration classes:
spring:
profiles:
default: test-default
group:
h2:
- test-default
- database
- h2
and configuration classes like
#Configuration
#EnableJpaRepositories(basePackageClasses = [OrderRepository::class] )
#EnableTransactionManagement
#EntityScan( basePackageClasses = [ OrderEntity::class])
#Profile("database")
class DatabaseConfiguration {}
I'd like to write a fast test with (#ContextConfiguration) e.g.
#ActiveProfiles("h2", "database", "test-default")
#ContextConfiguration( classes = [TestDefaultConfiguration::class])
internal class DbIngestionEventHandlerIntegrationTest()
I have to define both, h2 and database profiles, because ContextConfiguration does not load the application.yaml.
Is it possible to define spring profile groups programmatically? - so that they can be reused in tests?

DI in tests without using spring boot (#SpringBootTest)

Switching from spring boot back to "normal" spring because the app only uses some jdbc code to "upsert" into a postgresql database.
1)
tried annotating the test class with:
#RunWith(SpringJUnit4ClassRunner.class)
public class DBIntegration {
results in:
java.lang.IllegalStateException: Failed to load ApplicationContext
2)
tried annotating the class with:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {})
public class DBIntegration {
[main] INFO org.springframework.test.context.support.AbstractContextLoader - Could not detect default resource locations for test class [de.mydomain.myproject.DBIntegration]: no resource found for suffixes {-context.xml}.
No exceptions, but java.lang.Exception: No tests found matching [{ExactMatcher:fDisplayName=insertDataFrom_sometest],
3) tried annotating the class with:
#Component
public class DBIntegration {
dependency injection does not work in this case, the expected service
(to be injected) throws a nullpointerexception

Can Not Get #Component As A Bean In Unit Test For Spring Boot Application with Apache Camel

I am doing unit test for my Spring Boot application with Camel. When the application runs, it can get bean which is configured as a #Component
#Component("agencyExporterProcessor")
public class AgencyExporterProcessor {}
and I get the bean like this :
from(getTriggerExportEndpoint())
.routeId(getTriggerExportId())
// When shutting down, Camel will wait until the batch completed
.shutdownRunningTask(ShutdownRunningTask.CompleteAllTasks)
.log("[SamCustomExporter] - RouteId:${routeId} - Begin at ${date:now:MM/dd/yyyy HH:mm:ss.SSS}")
.setHeader(Messaging.Names.SAM_DATA_AGENCY_CONFIGURATION_HEADER_KEY.toString(), constant(getConfiguration()))
// Initialize a list to store exported CSV file names
.bean(agencyExporterProcessor, "prepareExportedFileList")
But when I test, the route cannot get the bean"
org.apache.camel.FailedToCreateRouteException: Failed to create route agencyExporterRoute_triggerExport at: >>> Bean[ref:agencyExporterProcessor method:prepareExportedFileList] <<< in route: Route(agencyExporterRoute_triggerExport)[[From[direct:agency... because of No bean could be found in the registry for: agencyExporterProcessor
This is how I configured my unit test class:
#DirtiesContext
#RunWith(SpringRunner.class)
#EnableAutoConfiguration
#SpringBootApplication
#SpringBootTest(classes = SamCustomExporterSpringApplication.class,
webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class AgencyExporterRouteTest extends BaseRouteTestSupport {}
Please give advice!!!! Many thanks
You should refer to the bean name as a String value in the Camel route:
.bean("agencyExporterProcessor", "prepareExportedFileList")

Spring Boot ConfigurationProperties fail to initialize for integration testing

Using gradle (3.4.1) with an integrationTest configuration, the tests using the ConfigurationProperties of Spring Boot (1.5.1.RELEASE) is failing to initialize even though the application initializes correctly (./gradlew bootRun). The class annotated with ConfigurationProperties is similar to the following
#Component
#ConfigurationProperties(prefix = "foo")
#Validated
public class AppConfiguration {
#NonNull
private URL serviceUrl;
...
The configuration file does have getters and setters. The error that is generated is similar to the following
java.lang.IllegalStateException: Failed to load ApplicationContext
....
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'AppConfiguration': Could not bind properties to AppConfiguration
....
Caused by: org.springframework.validation.BindException: org.springframework.boot.bind.RelaxedDataBinder$RelaxedBeanPropertyBindingResult
Field error in object 'foo' on field 'serviceUrl': rejected value [null]; codes ...
The configuration class of the integration test is annotated as follows
#Configuration
#ComponentScan(...)
#EnableConfigurationProperties
#EnableIntegration
public static class ContextConfiguration {}
The test class had the following annotations
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class ReleaseTest {
...
After looking at the Spring Boot code for the ConfigurationPropertiesBindingPostProcessor#postProcessBeforeInitialization() it suggested that the property source was not being discovered. Adding the org.springframework.boot:spring-boot-starter-test artifact as a compile-time dependency and modifying the context configuration of the test class to
#ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
the AppConfiguration class was initialized properly using a YAML-based properties file.
An alternative is to add
#TestPropertySource("classpath:/application.properties")
This approach doesn't require the spring-boot-starter-test dependency and requires that a "traditional" properties file is used (a YAML file will not work with this approach).

java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling

I have the following test class:
#ActiveProfiles({ "DataTC", "test" })
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {BaseTestConfiguration.class, DataTestConfiguration.class, JpaConfiguration.class, PropertyPlaceholderConfiguration.class })
public class RegularDayToTimeSlotsTest {
...
The issue seems to come from the BaseTestConfiguration class:
#Configuration
#ComponentScan(basePackages = { "com.bignibou" }, excludeFilters = { #Filter(type = FilterType.CUSTOM, value = RooRegexFilter.class),
#Filter(type = FilterType.ANNOTATION, value = Controller.class), #Filter(type = FilterType.ANNOTATION, value = ControllerAdvice.class) })
public class BaseTestConfiguration {
}
I systematically get this exception:
Caused by: java.lang.IllegalArgumentException: A ServletContext is required to configure default servlet handling
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer.<init>(DefaultServletHandlerConfigurer.java:54)
at org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.defaultServletHandlerMapping(WebMvcConfigurationSupport.java:329)
at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$bb4ceb44.CGLIB$defaultServletHandlerMapping$22(<generated>)
at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$bb4ceb44$$FastClassByCGLIB$$368bb5c1.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:326)
at org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration$$EnhancerByCGLIB$$bb4ceb44.defaultServletHandlerMapping(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
... 43 more
I am not sure how to get around this issue. Somehow Spring is looking for a ServletContext when I run the test and I get the above exception...
One of your #Configuration classes is obviously annotated with #EnableWebMvc. That's how DelegatingWebMvcConfiguration ends up in your stack trace, since it is imported by #EnableWebMvc.
So although you think you don't need a WebApplicationContext (and hence a ServletContext), you in fact do need it simply because you are loading an application context with #EnableWebMvc.
You have two options:
Compose the configuration classes for your integration test so that you are not including the web-related configuration (i.e., the #Configuration class(es) annotated with #EnableWebMvc).
Annotate your test class with #WebAppConfiguration as suggested in other comments above.
Regards,
Sam (author of the Spring TestContext Framework)
It seems like you are missing
#WebAppConfiguration
from your test class.
The documentation states
The resource base path is used behind the scenes to create a
MockServletContext which serves as the ServletContext for the test’s
WebApplicationContext.
Typically a Servlet container would provide the ServletContext. Since you are in a testing environment, you need a fake. #WebAppConfiguration provides that.
For you to instantiate the Servlet context, you would have to use the annotation.
#WebAppConfiguration
A class-level annotation that is used to declare that the ApplicationContext loaded for an integration test should be a WebApplicationContext. The mere presence of #WebAppConfiguration on a test class ensures that a WebApplicationContext will be loaded for the test, using the default value of "file:src/main/webapp" for the path to the root of the web application (i.e., the resource base path). The resource base path is used behind the scenes to create a MockServletContext which serves as the ServletContext for the test’s WebApplicationContext.
I was getting a similar error but whilst running the application normally rather than trying to run tests.
It turns out if you're making use of a custom PermissionEvaluator then you need to declare it in a separate #Configuration class to the one with your main Spring security configuration in.
See: How do I add method based security to a Spring Boot project?
There is also an open Github issue: https://github.com/spring-projects/spring-boot/issues/4875

Resources