Enable spring boot tests based on VM options - spring

I want to run some test classes and disable running some other test classes based on VM options.
What are the possible ways to achieve this?
VM option will be like : -DENABLE_FEATURE1_TEST=false -DENABLE_FEATURE2_TEST=true.
I have tried using Junit 5 property
#EnabledIfEnvironmentVariable(named = "ENABLE_FEATURE1_TEST", matches = "true")
on the test class, but using this still runs the tests in the class.
Similarly, i have also tried using #Conditional annotation, with no success.

-DENABLE_FEATURE1_TEST=false sets a JVM system property named ENABLE_FEATURE1_TEST, not an operating system environment variable.
So, you would need to use:
#EnabledIfSystemProperty(named = "ENABLE_FEATURE1_TEST", matches = "true")

Related

Spring Boot JUnit and #TestPropertySource using multiple property files

Spring Boot 2.0.3.RELEASE
Have more than one properties file to deal with .. the application.properties and application-DEV.properties
using the annotation #TestPropertySource in a Junit test I can only get it to read one file:
#TestPropertySource("file:C:\\Users\\user\\eclipse-workspace\\one2one_httpCall\\src\\main\\resources\\application-DEV.properties")
works as expected
However I need two properties file I did see the locations option but did not see an example of more than one file .. tried different options but none worked:
#TestPropertySource(locations = "classpath:application-DEV.properties;classpath:application.properties")
Tried a couple of ways I am not posting and even tried using #TestPropertySource twice but error saying u cannot use it twice.
tried using #PropertySource since u can use it twice but did not work since this is a Junit test. Looked at a bunch of questions on stacktrace + others and tried but no luck.
So my question is how to use two properties files via the #TestPropertySource annotation?
If you look inside the definition of #TestPropertySource, you will see that locations is of type String []. Therefore, if you need to pass it multiple values, you must do so with an array:
#TestPropertySource(locations = { "classpath:application.properties", "classpath:application-DEV.properties" })
Also, pay attention to the order in which you declare your properties files. As stated in the TestPropertySource docs:
Each location will be added to the enclosing Environment as its own property source, in the order declared.
So you would probably want to declare your DEV properties after to avoid them being overriden by your production properties.

Run integration tests only if specific spring profile is set

We have multiple test classes in our spring boot application. Some of the classes contain integration tests, some contain unit tests.
These means that if I (e.g. with maven) let all tests to be executed, it will run all tests in all classes.
What I like to achieve is that the integration tests are executed only, if a specific spring profile is set, e.g. via application.yml.
I like e.g. to annotate the whole test class to define that the tests in this class are only executed if the specified spring profile is set.
If it is not set, these tests shall be ignored.
The topic How can I use #IfProfileValue to test if a Profile is active? goes in exactly this direction. #IfProfileValue looks at first glance exactly like it is what I need.
But as it is pointed out, it is not. I could use it, if I would set a specific system property. But I need to use a real spring profile (and not the system property spring.profiles.active - this would ignore a profile set via application.yml)
#Profile seems to look also to be what I need but as the topic Use #Profile to decide to execute test class shows, we should not use it.
So what can be done to achieve this?
Note that there are a lot of questions about tests and spring profiles on stack overflow. But most of them point out how to set configurations in tests specific to spring profiles. That is not would I am looking for.
I would like to execute or ignore the tests.
I don't know exactly how you want to achieve it, but here is a way if you are using junit to conditionally ignore some tests at runtime simply using a configuration property:
application.properties:
test.enabled=true
then in your test code you can use org.junit.Assume and a property like the following:
#Value("${test.enabled}")
private Boolean testEnabled;
#Test
public void test {
org.junit.Assume.assumeTrue(testEnabled);
// your test code
}
now if you set the property test.enabled to true the test will run, otherwise it will be ignored.
Source: Conditionally ignoring tests in JUnit 4
Using JUnit 5, you can use an #Autowired Environment to check if a profile is active #BeforeEach test is run:
Assumptions.assumeTrue(Arrays.asList(this.environment.getActiveProfiles()).contains("integration"));
This checks for a profile named "integration" and works regardless of how the profile was set (system property, environment variable, application.yml, etc.).
If the profile is not active, the test will be ignored, which is similar to using the #Disabled annotation.
It is very easy. My solution in kotlin:
Create annotation
import org.springframework.test.context.junit.jupiter.EnabledIf
import kotlin.annotation.AnnotationRetention.RUNTIME
import kotlin.annotation.AnnotationTarget.CLASS
import kotlin.annotation.AnnotationTarget.FUNCTION
#Target(CLASS, FUNCTION)
#Retention(RUNTIME)
#EnabledIf(
expression = "#{environment.acceptsProfiles('integration')}",
reason = "🏋🏻‍ Because spring.profiles.active = integration",
loadContext = true)
annotation class Integration
Use it:
import by.package.Integration
#Integration
internal class IntegrationTest {
#Test
// #Integration
fun test() {
assertEquals(4, 2 + 2)
}
#DisableIf annotation has opposite logic

Set a property value in spring from a static field

I have a situation where I need a property value (application.name) before the application context is loaded - spring boot, before SpringApplication.run is called, and during context loading.
In my ApplicationMain class which calls SpringApplication.run, I have a constant public static final NAME = "MyApplicationName".
My issue is that we have some libraries that are injecting the value via #Value("${application.name}").
Is there a way set the application.name property in the context from this constant value?
I was thinking I could do a post-construct and then set it in the environment - similar to the solution described here, but that doesn't guarantee that it will be available for all injections by #Value.
I was hoping there was a similar mechanism to #Bean on a method which could set the value for the property, but I don't see one anywhere.
Variables can be injected on Spring Boot in several ways, but for me one of the best way is using operating system variables in *nix or Windows you can define variables like this:
Windows
SET APPLICATION_NAME = "MY APP"
*nix
export APPLICATION_NAME = "MY APP"
Be warned that the underline character (_) is replaced by . inside your application. Other way is using Java properties defined using -Dapplication.name="MY APP", that goes in your application command line. After you defined that variables in the operating system you can catch them in your code using:
#Value("${application.name}")
So, again, I recommend you using environmental variables to store your application configuration, so the operators or devops people will be able to change your application behavior without touch code or internal properties files (inside your application package).
Also another way is setting System properties (System.setProperty), that will make Java applications receive variables set in run-time. Actually is the same map (System map) used using -D in command line, however it is done in run-time instead of in command line. An example:
System.setProperty("application.name","MY APP");

Execute the same #SpringBootTest with different properties

I have a #SpringBootTest which is used to execute an integration test on the server. Depending on the configuration I want the server to behave differently. The configuration itself is read by beans (scope = singleton) deep inside my app logic and they read the property via #Value annotation.
How could I execute the same test with different configuration settings? I have tried to write different test classes and annotate them with #TestPropertySource(properties = XYZ). But it seems that this affects all other tests as well (due to the singleton scope?). It there a way to reset the properties after the test?
To respecify my problem: I want to configure my bean with a different #Value property during my tests and this value should only be valid throughout this specific test execution.
Thanks ahead for any pointers.
I have a webservice, which is connecting to the client of other webservice by using property from the config. As in any organization, we have different environments. For testing, I wanted to hit testing env instead of local. This is how I override the default property value only for integration test. By doing this, I can hit the test env instead of default local env.
#SpringBootTest(value = {"eureka.client.enabled=false", // Don't start Eureka
"com.somepackage.webservicename.client.serviceUrl = http://nodename.envname:26730"})
Hope this helps!

Spring boot, use profiles to load files

I have used spring-boot profiles to change property values for different environments, now I want to use the same approach to load different resource files, ie example I have dev_queries and prod_queries.xml with sql queries.
How can I make spring-boot load dev_queries.xml if active profile is dev and prod_queries.xml otherwise. I know that I can check the active profile but my idea is to do not add specific logic for handle this situation.
Would it help to externalize the filename as a custom property (docs, especially 24.4)? So that in your properties you would use:
# application-dev.properties
myapp.query-source=dev_queries.xml
# application-production.properties
myapp.query-source=prod_queries.xml
In your application beans this setting can be accessed by using the #Value annotation:
#Value("${myapp.query-source}")
private String querySource; // will be dev_queries.xml or prod_queries.xml
That way in the code where you are loading the xml file you don't have to conditionally check for the currently active profiles but can externalize that setting to the properties.

Resources