Dynamically change value from a property file in Spring Boot Cucumber test

Viewed 1224

I have a Spring Boot application in which a specific bean (MyClass) gets a @Value annotated property whose value is defined in application.properties file:

@Component
public class MyClass {
    
  private String type;

  public MyClass(@Value("${type}") String type) { 
    this.type=type;
  }

  public String doSomething () {...} 
}

application.properties file includes the following: type=typeA

The testing is done using Cucumber, and I would like to test the behavior of the method MyClass.doSomthing when the value of type is not typeA but typeB , so I thought about doing the following:

The scenario in the *.feature file will start like this:

Scenario: Validating doSomething when type is B
    Given The value of type is typeB
    Then Validate doSomething 

in the *StepDef file - the implementation of the Given step should somehow change the value of type to typeB, so that the flow of MyClass.doSomthing will process typeB:

@Given("The value of type is typeB")
public void changeTypeToB() {
    ...
}

My question is: How do I set the value of type to typeB (in the method changeTypeToB) considering the fact the during the test the Spring profile is the default one, hence the initial value of type is typeA ?

Thanks!

Dino

1 Answers

You are effectively trying to change a configuration value after the Spring application has already started.

This generally requires starting a new application context and in Cucumber terms this means starting a separate test suite.

You would organize this like so:

package com.example.stepdefinitions;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@CucumberOptions(
  extraGlue = "com.example.app.config.typea"
)
public class RunCucumberTestTypeA {

}

And:

package com.example.stepdefinitions;

import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;

@RunWith(Cucumber.class)
@CucumberOptions(
  extraGlue = "com.example.app.config.typeb"
)
public class RunCucumberTestTypeB {

}

Then use the context configuration to override the properties:

package com.example.app.config.typeb;

@CucumberContextConfiguration
@SpringBootTest(properties = {
        "com.example.value=Hello", 
        "com.example.value2=World"
})
public class CucumberTestContextConfiguration {

}

Or enable a profile and put your properties in application-type-b.yml:

package com.example.app.config.typeb;

@CucumberContextConfiguration
@SpringBootTest
@ActiveProfiles("type-b")
public class CucumberTestContextConfiguration {

}

As a sanity check you can then verify if the right configuration is used in the The value of type is typeB step.

This is quite a bit of setup though. You can also create a new instance of MyClass that isn't managed by the spring application context and run your tests on that.

@Given("The value of type is typeB")
public void changeTypeToB() {
    testInstance = new MyClass("typeB")
}
@Then("validate doSomething")
public void changeTypeToB() {
    testInstance.doSomething()
    // validate test instance did something
}

Finally you may want to reconsider your design. It sounds like typeB could be a feature toggle (because you want to change it at runtime) in which case using @Value wouldn't be the right approach.

Related