Technology
Spring framework is the most used Java framework for developing all types of applications.
In the recent version of Spring( aka Spring 5), the spring-test artifact introduced the new annotation @DynamicProperySource, which will be used to resolve the properties during the run-time.
Also, Spring-test is integrated with the test container framework, which is mostly used for external system dependency applications.
It provides a container for each test instance so that we can run integration tests without relying on an external system.
It provides the containers for mostly used databases like MySql, Oracle, Postgres, etc.
The benefits of using a test container framework
Database Access layer integration tests
Using this containerized instance of database, developer/CI tools, no need to install the database software. As it is creating new instances for each test, we can execute the integration tests as needed without any dependency on the database state.
Application integration tests
For running your application in a short-lived test mode with dependencies, such as databases, message queues, or web servers.
UI/Acceptance tests
Use a containerized web browser compatible with Selenium for automated UI tests. Each test can get a new browser instance, without browser status, plugin variations, or automatic browser upgrades to worry about.
Custom Containers
This library will also provide an interface for creating new custom containers using GenericContainer as a base container.
For each type of container, we have a dependency for that type, suppose the application needs MySQL as a database, then we can add the below dependency in the pom.xml file:
<dependency> <groupId>org.testcontainers</groupId> <artifactId>mysql</artifactId> <version>1.13.0</version> <scope>test</scope> </dependency>
For each type of container, we have a dependency for that type, suppose the application needs MySQL as a database, then we can add the below dependency in the pom.xml file:
Let’s first understand the code needed for @DynamicPropertySource and then how to use it to reduce lines of code and make it more readable.
Suppose the application is based on a graph database like Neo4j, we need to create a container for it and use it in our tests.
As Neo4Jcontainer instance details are available at runtime, we need to configure using the spring-boot-test starter to provide the information to the test execution environment.
@SpringBootTest @Testcontainers @ContextConfiguration(initializers = ExampleIntegrationTests.Initializer.class) public class ExampleIntegrationTests { @Container private static Neo4jContainer < ? > neo4j = new Neo4jContainer < > (); static class Initializer implements ApplicationContextInitializer < ConfigurableApplicationContext > { @Override public void initialize(ConfigurableApplicationContext context) { TestPropertyValues.of("spring.data.neo4j.uri=" + neo4j.getBoltUrl()) .applyTo(context.getEnvironment()); } } }
Each time Neo4JContainer new instance is created, and host details are added to the environment using TestPropertyValues, and as we learned above we need to @Testcontainers and @Container from the testcontainers library.
Spring test 5 introduces the new annotation @DynamicPropertySource to provide the property to execution context run-time, but one thing need to remember is that the method used for this annotation must be static and the argument is of the type DynamicPropertyRegistry. Where these run-time properties will be added to the environment by the DynamicPropertyRegistry registry class.
So, if we use @DynamicPropertySource the above code will look like the below:
@SpringBootTest @Testcontainers class ExampleIntegrationTests { @Container static Neo4jContainer < ? > neo4j = new Neo4jContainer < > (); @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl); } }
One more important point is, that we are adding the properties to DynamicPropertyRegistry as key and supplier, these suppliers will only execute whenever a property is resolved.
Conclusion
We learned the new feature added in the spring-test 5 version, we also learned how the complex code can be converted to easily readable and easy maintainable code using this @DynamicPropertySource annotation.