我有一个Spring组件,它将Clock作为依赖项:
@Component
public class MyClass {
private final Clock clock;
@Autowired
public MyClass(Clock clock){
this.clock = clock
}
}
对于我的大多数测试,我有一个模拟时钟,注释为@Bean
并正确注入。但是,对于我的一些测试,我需要使用不同的模拟时钟。如何在这些测试中使用不同的模拟?
public class MyClassTest {
@Autowired
private MyClass myClass;
@Test
public void test1(){
// use the standard mock clock
}
@Test
public void test2(){
// inject clock.fixed(Instant.parse("2018-01-01T00:00:00Z"), UTC);
}
@Test
public void test3(){
// inject clock.fixed(Instant.parse("2019-12-12T23:59:59Z"), UTC);
}
}
因此,在此示例中,我想覆盖test2
和test3
中的模拟时钟。
答案 0 :(得分:0)
您可以使用ReflectionTestUtils注入各种模拟。它是为此目的而制作的。
@Test
public void test2(){
// inject clock.fixed(Instant.parse("2018-01-01T00:00:00Z"), UTC);
ReflectionTestUtils.setField(myClass, "clock", mockClock);
}
答案 1 :(得分:0)
我认为处理这种用例的正确方法是使用只有一个bean的Mockito lib,只需按需更改存根方法实现:
Worker
Mockito已经由spring-boot-starter-test提供。
答案 2 :(得分:0)
让我们看看你拥有的所有选项。
就像在其他答案中建议的那样,如果字段是私有的或者创建了一个setter,则可以使用ReflectionTestUtils
。这是一个简单的方法,但它有一些你应该注意的缺点。
如果MyClass
调用其他类OtherClockClient
,那么它也使用时钟,类不知道这样的替换,你可能会出现不一致,因为两个时钟就在附近。
另一个问题是手动更换会破坏弹簧环境。这很重要,因为默认情况下在测试之间重用spring上下文,并且不保证测试顺序。这意味着可能会在test2
之前执行test1
并且test1
中不会使用“标准”时钟。如果test1
依赖于隐式设置“标准”时钟的行为,则会遇到麻烦。
要解决此问题,您可以使用@DirtiesContext
标记测试,也可以手动还原依赖项。
您始终可以在测试中注入相同的时钟,默认情况下,它应该演示您命名为“standard”的行为。但是,它可以提供额外的API,允许测试根据需要配置时钟。
public class ConfigurableClock implements Clock {
void fixAt(Instant instant) {
}
}
public class MyClassTest {
@Autowired
private ConfigurableClock clock;
@Test
public void test1() {
// use standard clock behaviour
}
@Test
public void test2(){
clock.fixAt(Instant.parse("2018-01-01T00:00:00Z"));
}
在这种情况下,不需要重新连接bean,但仍应重置状态,以便期望隐式默认时钟的测试具有它。您可以使用@Before
/ @After
方法重置时钟:
@Before
public setUp() {
clock.reset();
}
@After
public tearDown() {
clock.reset();
}
或添加TestExecutionListener即可。