【发布时间】:2021-07-30 15:33:22
【问题描述】:
对于我的 Java Spring 测试,我决定伪造系统时钟以使测试更容易
我有一个继承公共基类的测试 bean
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc(print = MockMvcPrint.LOG_DEBUG)
@TestExecutionListeners(mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS,
value = {FlywayTestExecutionListener.class}
)
@FlywayTest
@Getter(AccessLevel.PROTECTED)
public abstract class AbstractMockMvcTest {}
@Configuration
@Sql(scripts = "classpath:..", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
@Sql(scripts = "classpath:..", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
@WithMockUser(username = "junit", authorities = {}, roles = {})
class RolesControllerTest extends AbstractMockMvcTest {
private final Instant fixedInstant = Instant.from(OffsetDateTime.of(2021, 6, 2, 15, 54, 0, 0, ZoneOffset.ofHours(2)));
@Bean
Clock fakeClock() {
return Clock.fixed(fixedInstant, ZoneId.ofOffset("UTC", ZoneOffset.ofHours(2)));
}
}
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@ConditionalOnMissingBean(Clock.class)
@Bean
public Clock systemClock() {
return Clock.systemUTC();
}
}
这个想法是我的应用程序声明了一个主时钟,每个需要访问时间的 bean 都使用它(例如 getClock().instant() 或 Instant.now(getClock()))。通过模拟时钟,我让测试变得更容易。
但我发现使用 Spring bean 比使用 Mockito 更自然。 Java Clock 具有正确模拟时钟的方法
应用程序的最佳实践是将时钟传递给任何需要当前时刻的方法。依赖注入框架是实现此目的的一种方法:
public class MyBean {
private Clock clock; // dependency inject
...
public void process(LocalDate eventDate) {
if (eventDate.isBefore(LocalDate.now(clock)) {
...
}
}
}
这种方法允许在测试期间使用备用时钟,例如固定时钟或偏移时钟。
但是当我尝试运行测试时,我偶然发现了这个
@AutoConfigureMockMvc cannot be used in combination with the @Component annotation @Configuration
在 Web MVC 测试中声明额外的主 bean 有什么聪明的想法吗?
【问题讨论】:
标签: java spring-boot spring-test mockmvc junit-jupiter