How to override application-test.yml in spring boot test? - java

I have src/main/test/resources/application-test.yml, as per SpringBootTest it will load application.yml and then loads application-test.yml. But I face a scenario where I want to override certain properties in application-test.yml only for one test but other test needs to use properties from application-test.yml. How would I do this ?
I tried to use the #TestPropertySource annotation to override but it is not working.
#Slf4j
#RunWith(SpringRunner.class)
#SpringBootTest(classes= MyApplicationTestApplication.class)
#ActiveProfiles("test")
#DirtiesContext
#TestPropertySource(locations = {"classpath:application-test.yml",
"classpath:file-test.properties"})

Thanks for comments and answer , just wanted to add which worked for me
#SpringBootTest(properties = "some.property=localhost:9094")
Link to doc

What about creating one more profile and activate both of them (order matters) #ActiveProfiles({"test", "test-override"})
Or you can just override using System.properties, for example in static block, before spring context starts loading itself.

Related

Spring #Value always returns a null value

I'm facing an issue with a dev I have to do with Spring (not spring boot).
In a class, I have to retrieve the value of a property defined on a properties files (application.properties).
So, I use the #Value annotation (normally it's easy to use), but it doesn't work in my case.
In my class, I have this code :
#Value("${value:'DefaultValue'}")
private String myValue;
with the import : import org.springframework.beans.factory.annotation.Value;
My property file contains : value=a value
But, when I want to test my application, I always receive a null value (also with the use of the default value).
I try to add deafferents annotations in my class like
#Component
...
Do you have any suggestion? I'm pretty sure I miss a config somewhere, but I don't know what.
Thanks in advance
Tigrou
Every class where you use #Value annotation MUST be a spring-managed bean. You can achieve this by adding #Component annotation but make sure that you have configured component scan #ComponentScan(basePackages = "your.package") in your java configuration, so spring knows where to search for components.
Finally, with the help of everybody here (special thanks to #M. Deinum I fixed my issue.
So, first thing done, replace the Junit dependeny (use) by a Spring test dependency.
secondly, I've updated my test to be executed with Spring with those lines :
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {AppConfig.class})
This was enough to retrieve the default value of the #Value field.
To retrieve the value I had to add
#PropertySource("classpath:application.properties")
in my AppConfig class

Spring boot override application properties in test

If I have a appplication.properties like:
url=someUrl
user=userOne
password=ABCD
But if I want to be able to set the password when testing to something else, lets say:
password=someTest
How do I do that?
I need to do this in one test
#Test
void checkSomething{
//change/override password before calling someMethod only for this test
someMethod();
}
You can create a testing profile file something like application-testing.properties and specify the overridden properties there.
Now while running the application you can specify use profile using
-Dspring.active.profiles=testing
There are multiple ways.
1st way: Spring Profile
aplication.yaml:
spring.profiles.active=dev
---
spring.profile=dev
url=someUrl
user=userOne
password=ABCD
---
spring.profile=test
password=someTest
Test class:
#RunWith(SpringRunner.class)
#SpringBootTest
#ActiveProfiles("test")
public class MyTestClass {...
2nd way: SpringBootTest Properties
#RunWith(SpringRunner.class)
#SpringBootTest(properties = { "password=someTest" })
public class MyTestClass {...
create another application.properties under src/test/resources thats all you need,
if you want to get properties to use in one method you can do i without involving spring :
InputStream input = Main.class.getResourceAsStream(yourproperties-path);
Properties prop = System.getProperties();
prop.load(input);

Add a spring profile to the existing ones in a SpringBootTest

I have a SpringBootTest and I want to add a spring-profile to the existing ones for a specific tests. I tried #SpringBootTest(webEnvironment = RANDOM_PORT, properties = "spring.profiles.include=my-second-profile") which was suggested in https://github.com/spring-projects/spring-boot/issues/7668 but this doesn't work at all. Only the profile which was included is active now. As a result my context does not start because required properties from the default active profiles are missing. Has anyone an idea how to solve this problem?
Thanks!
properties expects an array String[] not a single object String.
#SpringBootTest(webEnvironment = RANDOM_PORT, properties = {"spring.profiles.include=my-second-profile"})
Surround your String with {} and it should work.
The approach that works for me is using the separate #ActiveProfiles annotation, and not necessarily use the properties as you do. #ActiveProfiles expects a comma-separated string of profile names. So your annotations could become as follows:
#SpringBootTest(webEnvironment = RANDOM_PORT)
#ActiveProfiles(profiles = "main-profile,my-second-profile,other-profile")

How can I use #SpringBootTest(webEnvironment) with #DataJpaTest?

I am trying to test a JAX-RS application but I'd rather not mock the data especially since there's a buildData method for an existing #DataJpaTest
Here's what I am trying so far:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = MyApp.class
)
#DirtiesContext
#DataJpaTest
public class MyResourceTest {
I get the following error
java.lang.IllegalStateException: Configuration error: found multiple declarations of #BootstrapWith for test class [app.MyResourceTest]: [#org.springframework.test.context.BootstrapWith(value=class org.springframework.boot.test.context.SpringBootTestContextBootstrapper), #org.springframework.test.context.BootstrapWith(value=class org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTestContextBootstrapper)]
The other ones I saw that are similar do not talk about the webEnvironment setting:
How do I import configuration classes in a #DataJpaTest in a SpringBootTest?
Recommended way to remove #DataJpaTest when used along with #SpringBootTest
There is somewhat of a solution using #AutoConfigureTestDatabase but when I did that only the first one works because buildData is annotated with #Before (same as in #DataJpaTest) as I want the data to be pristine before each test so I can do failure scenarios.
Switching to #BeforeClass also won't work because I won't be able to use the #Autowire Repository objects.
The #DataJpaTest documentation states the following:
If you are looking to load your full application configuration, but use an embedded database, you should consider #SpringBootTest combined with #AutoConfigureTestDatabase rather than this annotation.
Keep in mind that #DataJpaTest is annotated with #Transactional and #DirtiesContext. So you may need those annotations along with #AutoConfigureTestDatabase.
Actually when doing the answer in https://stackoverflow.com/a/57609911/242042, it solves the immediate problem, but you won't be able to do any tests that involve the database using a REST client as #Transactional will prevent the data from being saved for the client to get.
To get this to work, #Transactional should not be used. Instead DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD should be used instead. This dramatically slows down each test (as in 1 second to 10 seconds per test) but at least it works.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = MyApp.class
)
#DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
#AutoConfigureTestDatabase
#AutoConfigureWebTestClient
public class MyResourceTest {
#Autowired
private TestRestTemplate restTemplate;
...
}

Specifying classes loading order in #ContextConfiguration in JUnit test cases

I am using junit 4.11 and spring-test-4.1.5 for writing integration test cases. I am using #ContextConfiguration annotation to load the configurations.like,
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes ={ApplicationConfig.class,SpringConfiguration.class }, initializers = {CustomProfileResolver.class, AppInitializer.class}, loader = SpringApplicationContextLoader.class)
As you can see i am using two configuration classes.
The problem i am facing is i want to load the SpringConfiguration.class before ApplicationConfig.class. I tried with reversing the order but it didn't worked. Neither #order can be specified here.
So how to order the loading of these configuration classes, is it possible ?
#ContextConfiguration and its supporting classes (e.g., MergedContextConfiguration, AnnotationConfigContextLoader, AbstractTestContextBootstrapper, etc.) are intended to retain the original ordering of #Configuration classes declared via the classes attribute of #ContextConfiguration.
Thus, if you can verifiably prove that reversing the order of your SpringConfiguration and ApplicationConfig classes does not result in SpringConfiguration being processed first, then you have found a bug in Spring.
If you have found a bug, please report it in JIRA.
Thanks,
Sam
Use #ContextHierarchy
#ContextHierarchy({
#ContextConfiguration(classes = {SpringConfiguration.class}),
#ContextConfiguration(classes = {ApplicationConfig.class})
}

Categories