using ConfigFileApplicationContextInitializer does not resolve default values for #Value - spring-boot

When I am using:
#ContextConfiguration(classes = { DmiVehicleRTExportConfig.class },
initializers = ConfigFileApplicationContextInitializer.class)
my integration tests are failing as properties such as:
${oauth2client.prematureTimeout:600}
are not getting default value of 600.
This is resolved through using: SpringApplicationConfiguration but I want to use ConfigFileApplicationContextInitializer.class instead of SpringApplicationConfiguration.
Thanks.

I had the same issue. PropertySourcesPlaceholderConfigurer.class needs to be added:
#ContextConfiguration(classes = { DmiVehicleRTExportConfig.class,
PropertySourcesPlaceholderConfigurer.class },
initializers = ConfigFileApplicationContextInitializer.class)
Spring team has just added a note about that:
Using ConfigFileApplicationContextInitializer alone won’t provide support for #Value("${…​}") injection. Its only job is to ensure that application.properties files are loaded into Spring’s Environment. For #Value support you need to either additionally configure a PropertySourcesPlaceholderConfigurer or use #SpringBootTest where one will be auto-configured for you.

I had this problem in JUnit tests also when using
#SpringApplicationConfiguration
I solve this by adding a class with a 'static void main()' method to the configuration classes :
#Configuration
public class SpringEmptyApplication{
public static void main(String[] args) {
SpringApplication.run(SpringBootEmptyApplication.class);
}
}
I put this class as first to the list of configuration classes like
#SpringApplicationConfiguration(classes = {
SpringBootEmptyApplication.class,
DmiVehicleRTExportConfig.class
})
This works perfect for me.
If you want to avoid
#SpringApplicationConfiguration
you can try
#ContextConfiguration(loader = SpringApplicationContextLoader.class ...
This is how #SpringApplicationConfiguration itself is annotated, may be this loader can fix the problem, did not try...

Related

Spring boot - How to set an Application Property #Value only for a particular class

We use an application property to enable/disable a functionality.
#Component
#ConditionalOnProperty(
value = "spring.redis.cache.producer.enabled",
havingValue = "true")
public class MyEntityListener {
// Omitted
}
But we don't want to activate this in most part of our test base, so we are adding a TestPropertySource and try to get rid of it after class using #DirtiesContext
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#TestPropertySource(properties = {"spring.redis.cache.producer.enabled=true", "spring.redis.cache.listener.enabled=true"})
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
#DirtiesContext
public class AimaCacheControllerTest {
// Omitted
}
But the Spring Application context is not necessarily restarted after this class, breaking many consequent tests. Since mvn surefire plugin is running the tests in random order, it is not an option to do #DirtiesContext(classMode=BEFORE_CLASS) in the following tests - as we don't know which one that will be.
So the main issue here is to be able to inject an application property and make sure it is reset after the tests are over. How would we achieve that?
I feel like this should be quite common case but I couldn't find any working solution yet.

Not able to prevent couchbase autoconfiguration during tests

I am trying to prevent the application from attempting to connect to the DB while running the Unit tests. Following is what I have done.
#SpringBootApplication(exclude = {
CouchbaseDataAutoConfiguration.class,
CouchbaseAutoConfiguration.class,
})
#ComponentScan(excludeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
ApplicationStartup.class, MessageApplication.class }))
public class MessageApplicationTests {
public static void main(String[] args) {
SpringApplication.run(MessageApplicationTests.class, args);
}
}
#ActiveProfiles("test")
#SpringBootTest(classes = MessageApplicationTests.class)
class TestClass {
#Autowired
Serviceclass serviceclass;
#Test
void testMethod() {
}
}
Apart from this, I have added the following in application-test.yml
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration
- org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration
- org.springframework.cloud.aws.autoconfigure.messaging.MessagingAutoConfiguration
Both are not helping.
Can someone help me understand what is wrong here?
Also exclude your Config class (the one that extends AbstractCouchbaseConfig)
But if you have any references to repositories such as via Autowire or as args to #Service constructors, the application will fail to start. The exclude of auto configuration classes did not seem to matter when I tried it.
#ComponentScan(excludeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
ApplicationStartup.class, MessageApplication.class, Config.class}))
Probably not related to your issue, but I found that with multiple #SpringBootApplication classes (you have MessageApplication and MessageApplicationTests, right?), that Spring goes through the auto-config classes for both of them, not just the one in
SpringApplication.run(MessageApplicationTests.class, args) ) So one would need #SpringBootApplication excludes on both classes to completely exclude them (although I found that excluding didn't change anything).
The spring-data-couchbase project tests provide a mock couchbase server (src/test/resources/integration.properties -> mocked) or can use a standalone couchbase server (unmanaged). That might be useful for your testing.
The above answer posted by Michael Reiche is correct. Adding few more points to address the concern raised by him.
We need to exclude the configuration class for Couchbase. But the autowired repository beans would create a problem then.
To resolve it we can mock the repository beans so that it doesn't try to create actual repository beans and load them to the context.
Not including the autoconfiguration classes in the exclusion list did matter for me, as it would try to configure the Couchbase since the dependency is there in the classpath
#SpringBootApplication(exclude = {
CouchbaseDataAutoConfiguration.class, CouchbaseAutoConfiguration.class,
CouchbaseRepositoriesAutoConfiguration.class, CouchbaseReactiveDataAutoConfiguration.class,
CouchbaseReactiveHealthContributorAutoConfiguration.class
})
#ComponentScan(excludeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {
ApplicationStartup.class, MessageApplication.class , CouchBaseConfiguration.class }))
public class MessageApplicationTests {
#MockBean
Repositoryclass repoBean;

How to exclude/disable a specific auto-configuration in Spring boot 1.4.0 for #DataJpaTest?

I am using the #DataJpaTest from Spring for my test which will then use H2 as in memory database as described here . I'm also using Flyway for production. However once the test starts FLyway kicks in and reads the SQL file. How can I exclude the FlywayAutoConfiguration and keep the rest as described here in spring documentation in order to let Hibernate create the tables in H2 for me?
#RunWith(SpringRunner.class)
#DataJpaTest
public class MyRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private MyRepository triggerRepository;
}
Have you tried the #OverrideAutoConfiguration annotation?
It says it "can be used to override #EnableAutoConfiguration".
I'm assuming that from there you can somehow exclude FlywayAutoConfiguration
like so:
#EnableAutoConfiguration(exclude=FlywayAutoConfiguration.class)
Adding the dependency on an in-memory database to my build.gradle
e.g. testRuntime "com.h2database:h2:1.4.194"
And adding flyway.enabled=false to application.properties in src/test/resources worked for me.
I am converting an old JDBC app into a spring-data-jpa app and I'm working on the first tests now. I kept seeing a security module instantiation error from spring-boot as it tried to bootstrap the security setup, even though #DataJpaTest should theoretically be excluding it.
My problem with the security module probably stems from the pre-existing implementation which I inherited using PropertySourcesPlaceholderConfigurer (via my PropertySpringConfig import below)
Following the docs here:
http://docs.spring.io/spring-boot/docs/1.4.x/reference/htmlsingle/#test-auto-configuration
and your comments on #LiviaMorunianu's answer, I managed to work my way past every spring-boot exception and get JUnit to run with an auto-configured embedded DB.
My main/production spring-boot bootstrap class bootstraps everything including the stuff I want to exclude from my tests. So instead of using #DataJpaTest, I copied much of what it is doing, using #Import to bring in the centralized configurations that every test / live setup will use.
I also had issues because of the package structure I use, since initially I was running the test which was based in com.mycompany.repositories and it didn't find the entities in com.mycompany.entities.
Below are the relevant classes.
JUnit Test
#RunWith(SpringRunner.class)
#Transactional
#Import({TestConfiguration.class, LiveConfiguration.class})
public class ForecastRepositoryTests {
#Autowired
ForecastRepository repository;
Forecast forecast;
#Before
public void setUp() {
forecast = createDummyForecast(TEST_NAME, 12345L);
}
#Test
public void testFindSavedForecastById() {
forecast = repository.save(forecast);
assertThat(repository.findOne(forecast.getId()), is(forecast));
}
Live Configuration
#Configuration
#EnableJpaRepositories(basePackages = {"com.mycompany.repository"})
#EntityScan(basePackages = {"com.mycompany.entity"})
#Import({PropertySpringConfig.class})
public class LiveConfiguration {}
Test Configuration
#OverrideAutoConfiguration(enabled = false)
#ImportAutoConfiguration(value = {
CacheAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
TransactionAutoConfiguration.class,
TestDatabaseAutoConfiguration.class,
TestEntityManagerAutoConfiguration.class })
public class TestConfiguration {
// lots of bean definitions...
}
PropertySpringConfig
#Configuration
public class PropertySpringConfig {
#Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer()
throws IOException {
return new CorePropertySourcesPlaceholderConfigurer(
System.getProperties());
}
}
In my particular case, i needed to disable the FlywayDB on in-memory integration tests. These are using a set of spring annotations for auto-configuring a limited applicationContext.
#ImportAutoConfiguration(value = TestConfig.class, exclude = FlywayAutoConfiguration.class)
the exclude could effectively further limit the set of beans initiated for this test
I had the same problem with my DbUnit tests defined in Spock test classes. In my case I was able to disable the Flyway migration and managed to initialize the H2 test database tables like this:
#SpringBootTest(classes = MyApplication.class, webEnvironment = SpringBootTest.WebEnvironment.NONE,
properties = ["flyway.enabled=false", "spring.datasource.schema=db/migration/h2/V1__init.sql"])
I added this annotation to my Spock test specification class. Also, I was only able to make it work if I also added the context configuration annotation:
#ContextConfiguration(classes = MyApplication.class)
I resolved the same issue by excluding the autoconfiguration from my application definition, i.e.
#SpringBootApplication(exclude = {FlywayAutoConfiguration.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
you can also sue the following annotation:
#RunWith(SpringRunner.class)
#DataJpaTest(excludeAutoConfiguration = {MySqlConfiguration.class, ...})
public class TheClassYouAreUnitTesting {
}
You can just disable it in your test yaml file:
flyway.enabled: false

Prevent Application / CommandLineRunner classes from executing during JUnit testing

If in your TestCase class there is this annotations:
#SpringApplicationConfiguration(classes = {Application.class})
this will cause the Application.class, implementing the CommandLineRunner interface, to run the required method
public void run(String... args) throws Exception
I still think this is, mostly, a not wanted behaviour, since in your test environment you may not want to launch the entire application.
I have in mind two solution to circumvent this problem:
to remove the CommandLineRunner interface from my Application class
to have a different context for testing
Both this solution requires lot of coding.
Do you have a more convenient solution?
Jan's solution can be achieved easier.
In your test class, activate the "test" profile:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("test")
public class MyFancyTest {}
In your CommandLineRunner set the profile to NOT test:
#Component
#Profile("!test")
public class JobCommandLineRunner implements CommandLineRunner {}
Then you don't have to manually set the profile in the Application.
As mentioned in the spring documentation you can use #ContextConfiguration with a special initializer:
ConfigDataApplicationContextInitializer is an ApplicationContextInitializer that you can apply to your tests to load Spring Boot application.properties files. You can use it when you do not need the full set of features provided by #SpringBootTest
In this example anyComponent is initialized and properties are injected, but run(args) methods won't be executed. (Application.class is my main spring entry point)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = Application.class,
initializers = ConfigDataApplicationContextInitializer.class)
public class ExtractorTest {
#Autowired
AnyComponent anyComponent;
#Test
public void testAnyComponent() {
anyComponent.anyMethod(anyArgument);
}
}
You can define a test configuration in the same package as your application that looks exactly the same, except that it excludes beans implementing CommandLineRunner. The key here is #ComponentScan.excludeFilters:
#Configuration
#ComponentScan(excludeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = CommandLineRunner.class))
#EnableAutoConfiguration
public class TestApplicationConfiguration {
}
Then, just replace the configuration on your test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = TestApplicationConfiguration.class)
public class SomeApplicationTest {
...
}
No CommandLineRunner will be executed now, because they are not part of the configuration.
I'm a bit late to the party, but a reasonable approach is to mark the bean with #ConditionalOnProperty, e.g.
#ConditionalOnProperty(prefix = "job.autorun", name = "enabled", havingValue = "true", matchIfMissing = true)
public CommandLineRunner myRunner() {...}
The following annotation will then disable it in tests:
#SpringBootTest(properties = {"job.autorun.enabled=false"})
If you have a mocking framework installed (e.g. MockMVC) you can create a mock instance of the CommandLineRunner implementation, more or less disabling it:
#MockBean
private TextProcessor myProcessor;
Previous answers didn't work wor me. I ended up using different profiles - example for the init method in Spring Boot:
SpringApplication app = new SpringApplication(AppConfig.class);
app.setAdditionalProfiles("production");
app.run(args);
This is not executed during the tests so we're safe here.
All tests have their own profile "test" (which is useful in many other ways, too):
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("test")
public class MyFancyTest {}
The command-line runner is annotated with the "production" profile so the tests ignore it:
#Component
#Profile("production")
public class JobCommandLineRunner implements CommandLineRunner {}
I solve this by not implementing CommandLineRunner. Just get a bean from the context, and call a method on it, passing argv. That way you will get the same result, and the application won't start automatically when running the tests.

Spring Testing: How to enable auto-scan of beans

For example, now in each test class I have to do
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
I want to get rid of
#ContextConfiguration(loader=AnnotationConfigContextLoader.class)
and want Spring to scan all the beans in my project.
How can I do that?
You can do this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class MyTest {
#Test
public void testSomething() {
}
#Configuration
#ComponentScan("basepackage")
public static class SpringConfig {
}
}
By default #ContextConfiguration will look for static inner classes annotated with #Configuration, which is why this set up will just work.
You can get rid of loader param altogether, that is not required
If you have your spring configuration in an xml file you would use something like:
#ContextConfiguration(locations="classpath:applicationContext.xml")
If you use Java Config then you would use
#ContextConfiguration(classes=Config.class)
I used generic names in the above samples, you'll of course need to adapt to your project's configuration.
In both cases Spring's component scanning will need to be enabled for Spring to pickup the annotated classes.
You can also simply add #SpringBootTest if using Spring Boot.
#TestConfiguration
#ComponentScan("basepackage")
public class TestConfig{
}
Adding a config class lets spring to load application context.
This solved this issue for me.

Resources