33

Consider the following example:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
    properties = {
        "some.property=valueA"
    })
public class ServiceTest {
    @Test
    public void testA() { ... }

    @Test
    public void testB() { ... }

    @Test
    public void testC() { ... }
}

I'm using SpringBootTest annotation's properties attribute to set some.property property's value for all tests in this test suite. Now I'd like to set another value of this property for one of this tests (let's say testC) without affecting the others. How can I achieve this? I've read the "Testing" chapter of Spring Boot docs, but I haven't found anything that'd match my use case.

korolar
  • 1,340
  • 1
  • 11
  • 20
  • 1
    If you need to configure just a few properties, you can use the new @DynamicPropertySource annotation. https://stackoverflow.com/a/60941845/8650621 – Felipe Desiderati Mar 31 '20 at 01:01

5 Answers5

20

Your properties are evaluated by Spring during the Spring context loading.
So you cannot change them after the container has started.

As workaround, you could split the methods in multiple classes that so would create their own Spring context. But beware as it may be a bad idea as tests execution should be fast.

A better way could be having a setter in the class under test that injects the some.property value and using this method in the test to change programmatically the value.

private String someProperty;

@Value("${some.property}")
public void setSomeProperty(String someProperty) {
    this.someProperty = someProperty;
}
davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • 8
    I can't see how changing the source code for the sake of a test could be a good idea – Christian Vincenzo Traina May 31 '22 at 15:36
  • 2
    @ChristianVincenzoTraina Code without tests is bad. If the code isn't written in a way that can be tested, it's bad and has to change. If you know how to solve this without changing the code, please post an answer. – Aaron Digulla Oct 13 '22 at 07:24
13

Update

Possible at least with Spring 5.2.5 and Spring Boot 2.2.6

@DynamicPropertySource
static void dynamicProperties(DynamicPropertyRegistry registry) {
    registry.add("some.property", () -> "valueA");
}
timguy
  • 2,063
  • 2
  • 21
  • 40
  • how to change the property value in test case C? – firstpostcommenter Aug 21 '22 at 19:05
  • This isn't possible because the spring context and hence the properties are only loaded once for the whole test class. For details see the other reply and accepted answer here: https://stackoverflow.com/a/48570867/3276902 – timguy Aug 22 '22 at 21:08
3

Just another solution in case you are using @ConfigurationProperties:

@Test
void do_stuff(@Autowired MyProperties properties){
  properties.setSomething(...);
  ...
}
Sam
  • 1,832
  • 19
  • 35
  • 2
    I think that this would be changed for all other tests in this class as well if this method runs first. – Wim Deblauwe Feb 16 '21 at 07:36
  • I guess so but we could also autowire the properties into the setup method and set up the defaults there – Sam Feb 17 '21 at 02:47
3

With JUnit 5, you should be able to reduce the necessary code by using nested tests. Add the default config to the outer test class and the override annotations to the nested tests.

See also:

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
0

I hit the same problem with one of my integration tests, but I prefer to use @ConfigurationProperties in my code and that was key here.

After getting nowhere trying to set properties through various other methods, I realised I could just autowire my properties class and simply set the value I wanted in each specific test.

NB: If this were a unit test, I would have been able to mock my properties class just as easily.

jeremyt
  • 510
  • 4
  • 6