Consider a Spring component like:
@Component
public class Calculator {
@Value("${rate:1.0}")
private Double rate;
...
}
In a test, I'd like to instantiate three beans of this class based on the settings for property rate
:
It's easy to achieve this by writing three @SpringBootTest
s, each with its own @TestPropertySource
.
However, the result is rather ugly (the real production code is more complex than the simple example here).
Is there a way to instantiate three instances of the @Component
, each based on a given @TestPropertySource
?
I tried doing this in a @Configuration
class; something like:
@Configuration
@TestPropertySource(properties = {"rate=2.0"})
@ContextConfiguration(classes = {Calculator.class})
class PositiveRateCalculatorConfig {
@Autowired
private Calculator calc;
@Bean
Calculator positiveRateCalculator() {
return calc;
}
}
But I didn't manage to auto-wire Calculator into the config class in such a way that @TestPropertySource
takes effect.
Assuming there is only one Calculator
-bean in production and you want to test multiple configuration scenarios.
This is an excellent example of why the usage of @Autowired
and @Value
on fields is a bad practice. It kills tests..
Use @Value
in a constructor
@Component
public class Calculator {
private final Double rate;
Caluclator (@Value("${rate:1.0}") Double rate){
}
...
}
Now unit tests are easy
public class CalulatorTest {
@Test
void positiveRate(){
Calculator calculator = new Calulator(3d);
...
}
@Test
void negativeRate(){
Calculator calculator = new Calulator(-3d);
...
}
...
}
TIP: Avoid @Autowire
in other beans
Use constructor injection instead
@Service
public class DemoService{
private final Calculator calculator;
public DemoService(Calculator calculator) {
this.calculator = calculator;
}
}
And test
public DemoTest {
DemoService service = new DemoService(new Calculator(2d));
@Test
void test(){
....
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.