spring-bootkotlinparameterized-unit-test

changing configuration value in spring-boot app with values of parameterized test


I use this in my MyService.kt.
The useXml is read via application.yml and application-test.yml

@Service
class MyService (
    @Value("\${something.use-xml}")
    var useXml: Boolean = false
) {

  if(useXml) {
    // do this
  } else {
    // do  that 
  }
....
}

this works as expected.

but for the testing I want to use both variation:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("test")
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class MyFunctionalTest {

    @Value("\${something.use-xml}")
        var useXml: Boolean = false

  //....
@ParameterizedTest
@ValueSource(booleans = [true,false])
fun `do a parameterized test`(useXML : Boolean) {
    useXml = useXML // this is (of course) not setting the variations for `MyService.kt`
    if (useXML) {
      // test this  
    } else {
      // test that
    } 
      
}

I want a possibility where I can set the variable for the application.yml file, so both variations are tested.

Is there any way of doing it?


Solution

  • Of course, it is possible. You need to inject the service that you are testing and set its useXml value. In your case, it'll look like this:

    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
    @ActiveProfiles("test")
    @TestInstance(TestInstance.Lifecycle.PER_CLASS)
    internal class MyServiceTest {
    
        @Autowired
        private lateinit var myService: MyService
    
        @ParameterizedTest
        @ValueSource(booleans = [true,false])
        fun `do a parameterized test`(useXML : Boolean) {
            myService.useXml = useXML // you have to set the value for the test case
    
            Assertions.assertEquals(useXML, myService.useXml)
        }
    }
    

    However, if I were you and have such a case, I'd go with two totally separate implementations of the same interface, if xml and the other format have something in common. In the end, you will have two classes (you need better naming for that):

    1. MyServiceXml
    2. MyServiceJson

    Both this classes will be annotated will @ConditionalOnProperty("\${something.use-xml}") and they will be implementing the same interface.

    That will be very easy to test, two different implementations, so two different test classes.