Start Spring Boot context with remote config from JUnit Test - java

I am writing integration tests in a microservice environment. I want to fully initialize my Spring Boot application context once when running my JUnit test class. I can do this easily enough under normal circumstances, but in this case I need to load remote configuration from a Git repository (I am using spring-cloud-config). Under normal startup conditions, this Spring Boot application does successfully load the configuration from the Git repo. I am just trying to replicate the same context initialization during the test phase. Here is how I have written the test class:
#RunWith(SpringRunner.class)
#SpringBootTest(properties={"ENV=local","spring.cloud.config.enabled=true","spring.cloud.config.uri=http://config.server.com/config","ENCRYPT_KEY=secret"})
#ContextConfiguration(classes ={MyAppConfig.class,MyDBConfig.class})
#PropertySource({"classpath:spring-cloud-config.properties"})
public class MyIntegrationTest {
#Test
public void testFindUsersForCorp() {
System.out.println("Test is running ");
}
}
spring-cloud-config.properties:
spring.profiles.active=${ENV}
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
spring.cloud.consul.host=${CONSUL.HOST:localhost}
spring.cloud.consul.port=${CONSUL.PORT:8500}
spring.cloud.consul.discovery.healthCheckPath=/custom/health
spring.cloud.consul.discovery.healthCheckInterval=30s
spring.cloud.config.uri=${CONFIG.SERVER.URI:http://config.server:80/config}
spring.cloud.config.username=user
spring.cloud.config.password=${PASSWORD}
Logging output during Spring context initialization:
main WARN: Could not locate PropertySource: I/O error on GET request for "http://localhost:8888/userdata-service/default": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
main WARN: Cannot enhance #Configuration bean definition 'refreshScope' since its singleton instance has been created too early. The typical cause is a non-static #Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring such methods as 'static'.
main ERROR:
***************************
APPLICATION FAILED TO START
***************************
Description:
Cannot determine embedded database driver class for database type NONE
[OMITTED]
As seen above, the startup fails because no driver class for my persistance layer is defined. Since the relevant config is in Git, this error indicates that the remote configuration is not being fetched.
I appreciate any help anyone can offer. I will update this question with more information if needed.

Spring Cloud Config client should be initialized in bootstrap phase, so you should move corresponding properties from spring-cloud-config.properties to bootstrap.properties
See https://cloud.spring.io/spring-cloud-config/multi/multi__spring_cloud_config_client.html#config-first-bootstrap

Related

Spring: How to load my bean as the first bean when server startsup

I have a java application based upon spring and I have a bean that runs some connection test logic during server startup. If the connection test fails, I stop the server.
I need this bean as the first one to be loaded before any other beans performs some operations using the connection string.
Can someone help me figure out how I can load this connection test bean as the first bean please.
Ways tried:
Bean lifecycle hooks such as InitializingBean, init-method, #PostConstruct won't work as they will get invoked for my specific bean but can't control what beans gets loaded before my desired bean.
Update:
depends-on or #DependsOn worked.
Thanks

Run junit without data source persistence context in spring boot

In my spring boot application, there is a persistent context class for data source connectivity. While I write junit for this application, it always call this configuration class and fails when database connection is off. The junit didn't run if I exclude this configuration class. What is the solution to run the junit,even the database connectivity fails.

#TestConfiguration for Embedded Redis, same Redis Server for all Test classes

I use a Embedded Redis for integration testing. I set up my tests with Redis according to following article: https://www.baeldung.com/spring-embedded-redis.
The problem is, if I want to use the #TestConfiguration with several test classes, I get errors because #PreDestroy is not called. The Embedded Redis is created new each time and is not shared between the test classes. It is therefore tried every time to create a new Redis Sserver on the same port, which leads to the following error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testRedisConfiguration':
Invocation of init method failed; nested exception is java.lang.RuntimeException:
Can't start redis server. Check logs for details.
When I add the #DirtiesContext to all test classes I get following error:
java.lang.IllegalStateException: org.springframework.web.context.support.GenericWebApplicationContext#255e5e2e has been closed already
Is there a way to use the same Embedded Redis for all my test classes?
You can initialize the EmbeddedRedis in a method with #BeforeClass annotation. This will restrict your redis cache construction for the entire Test Class once.

Spring Boot: how to run a server at Spring Context startup and stop it during context shutdown during execution of tests?

My Spring Boot application uses a database server. During the tests, I would like to run an embedded version of the database. The server starts with a random port each time (it's from testcontainers.org).
First thing I tried was to use JUnit4's #ClassRule to start/stop the server, but Spring Boot is smart and re-uses contexts across test classes. So for a single test class everything works fine, but when I run tests in a package (or all tests), they fail due to this lifecycle difference.
Is it possible to somehow hook into tests execution and get a callback when Spring Boot Test infrastructure starts and stops a new context?
The most probable answer I will get is 'just add a server bean to the context when your tests run'. Ok, but here I face another problem:
How do I make sure that the server bean is initialized before other beans that talk to the server? #DependsOn does not seem to fit here as I do not want to have in production a bean annotated with #DependsOn("testServer")
Spring Boot is 2.1.6.

Spring Boot : Integration Test not excluding my Application configuration class

I have an application which connects to a zookeeper to perform operations on HBase. However, for Integration Tests, I have a class to create in-memory tables, and perform tests without trying to connect to said zookeeper.
I have defined a IntegrationTestAppConfig.class as follows:
#EnableAutoConfiguration(exclude = { AppConfig.class})
#ComponentScan
#Configuration
#EnableAsync
public class IntegrationTestAppConfig{
..... //this is where I create a bean for my HBaseConnectionManager to use my in-memory table environment
}
And, in my integration test class, I have the following:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = IntegrationTestAppConfig.class)
public class AHCLIManagerIT {
#Test
.....
}
Based on what I've read from the Spring-boot documentation, the integration test class should use IntegrationTestAppConfig.class for the application configuration.
However, when I run the Integration Test, I get an error saying connection to zookeeper timed out. In the stack trace, I see that the error occurred in AppConfig.java (my main class for app configuration), where it tries to create a HBaseConnection to the zookeeper.
I don't understand why my application is not using the App config class that I've defined in the annotations.
Is your AopConfig class actually an autoconfiguration class? Autoconfiguration classes are loaded by naming them in a spring.factories file in META-INF. The exclude attribute would only apply to those I believe. Auto configuration happens after regular app configuration anyways.
Also you have #ComponentScan on your config. If you really need to exclude AopConfig that would be the annotation I'd expect it to be on.
Though IMHO something doesn't seem right for doing a component scan in your tests

Categories