logo logo

Using Spring to Switch Environments in Automated Tests

main post image

When we create our automated tests, we don’t only want to run them in one test environment. We also don’t want to create one automated test per each test environment. However, we do want the capability to easily run our tests on different environments. One of the best and easiest way to manage test environments and environment properties is to use the Spring library. In this post, I will go over how we can do that for a Java-based project when we have TestNG or JUnit 5 based automated tests.

Using Spring to switch environments

It all starts with creating the automated tests. Once they are in place, we want to run them in different environments. These might include development environments, where developers commit often and might break things with their commits; test environments, where the deployed code is rather stable and commits are not as often; a staging environment where we are preparing for a release; or even production.

Because we are using different environments, there might be some values we require in our tests that are environment-specific. One good example is the URL of the environment, which we will use in tests to access the application or software we are testing. Another example might be the database connection details, which might have different values for each environment. Or we might even have some hardcoded properties, like some credentials we are using in the tests.

Based on all of these factors, a suitable solution for managing environment properties and easily working with them is to use the Spring library.

Setup

Before we can use Spring, we need to import it into our project. For a Maven project, this part is easily done by adding a few new dependencies in our pom.xml file. In my example below, 5.3.3 is the current latest available version for all these dependencies:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>5.3.3</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.3</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.3</version>
</dependency>

Once the dependencies are added, you should perform a clean install operation on the project.

Property file

The environment-specific properties should be written to property files. In the ‘src/main/resources’ folder of our project, we should create a dedicated folder, where we will store all our environment property files. In my case, I created a folder called ‘environments’.

Once we know where we will store these files, we will need to create one file for each environment we want to run tests on. For example, we could create a file for the dev environment, another one for the QA environment, one for staging, and another one for production. Of course, this all depends on what and how many environments you are using.

The name of each property file should reflect what environment it is referring to. Sometimes, several environments have URLs with a common domain name. In this case, the name of the files could be that part of the URL which is not common with the other environments. Or, as I mentioned earlier, we could have dedicated environments for different testing phases. Therefore, we could name the files, as an example: dev.properties, qa.properties, staging.properties and production.properties. The file extension does need to be .properties.

Once the files have been created, we can start adding properties to them. Each property is represented by a key/value pair. The key needs to be unique per file and represents the name of the property. The value does not need to be unique. Once a property is created in one of the environment files, it needs to be created in all existing environment files. Of course, in each file with the value corresponding to that environment. In the case we do not have any value for a property in a certain environment, we still need to add the property key in the corresponding file. We will simply not add any value.

As an example, we could create a URL property, which in the ‘dev.properties’ file would be:

url=dev.your.very.long.test.domain.com

The same property, in the ‘qa.properties’ file would have a different value:

url=qa.your.very.long.test.domain.com

Creating the application context file

In order for the environment functionality to be accessible from our tests, there is one more file we need to create. It is the so-called application context file. This is a configuration file basically, and its content needs to simply be the following (which you can copy-paste from here):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"></beans>

You should create the file in the ‘src/main/resources’ folder and name it ‘application-context.xml’, as a convention.

Now that we created the environment files and the application context, the tests need to be aware of these. This part is done through a bit of additional setup. This setup is slightly different between TestNG and JUnit 5. So below I will show you how to perform this setup for both test frameworks.

TestNG specific configuration

In case our test does not extend a base class (where common setup for multiple tests is done), we need to add the following code to our test class, right before the class name declaration:

@TestPropertySource("classpath:environments/${env}.properties") 
@ContextConfiguration("classpath*:application-context.xml")

The @TestPropertySource tells Spring where to find the environment property files. That is in the ‘environments’ folder in the classpath. The name of the file will be passed in when we run our tests from either IntelliJ or the command line. That is how the test will identify which file we need. The @ContextConfiguration simply tells Spring where to find the application context file it requires.

Additionally, our test needs to extend the AbstractTestNGSpringContextTests class. This same configuration can be applied to a base class, in case our test is extending one (if it is located in the ‘src/test/java‘ folder). The base class will extend AbstractTestNGSpringContextTests , and the test will then extend the base class.

The required imports for this code are:

import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.TestPropertySource; 
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;

JUnit 5 specific configuration

In case we are using JUnit 5 for our tests, and we are not extending any base class, we need to add the following code right before the class name declaration:

@TestPropertySource("classpath:environments/${env}.properties") 
@ContextConfiguration("classpath*:application-context.xml")
@ExtendWith(SpringExtension.class)

For JUnit 5, in this case, we don’t need to extend any context class from our test class. If our tests extend a base class (and it is found in ‘src/main/java‘), then the first 2 lines of the above code need to be moved to the base class. The third line needs to remain in the test class.

The required imports for this code are:

import org.junit.jupiter.api.extension.ExtendWith; 
import org.springframework.test.context.ContextConfiguration; 
import org.springframework.test.context.TestPropertySource; 
import org.springframework.test.context.junit.jupiter.SpringExtension;

Using environment properties in tests

Now that our tests ‘know’ which environment files to use, we need to specify what properties we are interested in. Let’s say we want to use the ‘url’ property in our test. We will store the value of this property to a field inside the test class. Therefore, we need to create a new field in the field declaration section of the test class. Reading the value of the property ‘url’ is done using the @Value annotation. We need to pass the name of the property (as it is in the property file), between the ‘${‘ and ‘}’ characters, as follows:

@Value("${url}") 
private String url;

Now, in the test, we will use the field we just created whenever we need the value of the property. The required import for the @Value annotation is:

import org.springframework.beans.factory.annotation.Value;

For best clarity, here is an example of a JUnit 5 test, in which I only print the value of the URL to the console:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@TestPropertySource("classpath:environments/${env}.properties")
@ContextConfiguration("classpath*:application-context.xml")
@ExtendWith(SpringExtension.class)
public class SpringEnvTest {
    @Value("${url}")
    private String url;

    @Test
    void firstTest() {
        System.out.println("url = " + url);
    }
}

Running tests and providing the environment values

The only remaining thing is to understand how we will switch the environment we are running our tests on. When we are running our tests directly from IntelliJ, without using the command line, we need to edit the test configuration. We just need to add, in the ‘VM options’ section of our test (whether TestNG or JUnit 5), the text ‘-Denv=nameOfEnvironment‘.

Here, ‘env’ corresponds to the placeholder we wrote inside our @TestSourceProperty annotations. The ‘nameOfEnvironment’ value needs to be one of the names of the existing environment property files. For example, if we want to run our test on the ‘dev’ environment, the VM options section in IntelliJ will be:

-Denv=dev

If instead of IntelliJ we are running our tests from the command line (for CI for example), in the Maven command we type for running the tests, we simply need to add the same text: -Denv=nameOfEnvironment.

For example, if we ran the test I just created, providing the value ‘qa’ in this command, the result would be:

url = qa.your.very.long.test.domain.com

Conclusion

When we want to run the same test on different environments, first we need to import the required Spring dependencies. Then, we need to create our environment files. Inside them, we will add all our environment-specific properties. We will then create the application context file. Inside the tests we will add a configuration, to provide the tests with the location of the environment files and the context file. In the tests, we will specify which properties we need. Then, we can easily switch between environments by providing their names as a test configuration parameter.

Happy Testing! 🌼

Avatar

About the author

Corina Pip

Corina is a Test & Automation Lead, with focus on testing by means of Java, Selenium, TestNG, Spring, Maven, and other cool frameworks and tools. Previous endeavours from her 11+ years testing career include working on navigation devices, in the online gaming industry, in the aviation software and automotive industries.
Apart from work, Corina is a testing blogger (https://imalittletester.com/) and a GitHub contributor (https://github.com/iamalittletester).
She is the creator of a wait based library for Selenium testing (https://github.com/iamalittletester/thewaiter) and creator of “The Little Tester” comic series (https://imalittletester.com/category/comics/). She also tweets at @imalittletester.

Join TestProject Community

Get full access to the world's first cloud-based, open source friendly testing community. Enjoy TestProject's end-to-end test automation Platform, Forum, Blog and Docs - All for FREE.

Join Us Now  

Leave a Reply

popup image

Selenium for Teams

Sharing and distributing Selenium tests has never been so easy! With TestProject's FREE Selenium based platform, you can finally create awesome tests with the freedom to collaborate with your team effortlessly.
Sign Up Now right arrow
FacebookLinkedInTwitterEmail