gpt4 book ai didi

java - 使用 Clock.fixed() 模拟 LocalDate.now(clock)

转载 作者:行者123 更新时间:2023-12-04 01:19:29 25 4
gpt4 key购买 nike

当我设置特定日期时,我正在努力测试我的端点。

我不想使用 PowerMock 来模拟静态方法,而是决定更改我的服务的实现并使用 LocalDate.now(Clock clock) 实现来更容易地测试它。

我添加到我的 SpringBootApplication 类:

@Bean
public Clock clock() {
return Clock.systemDefaultZone();
}

并将其自动连接到我的服务

@Autowired
private Clock clock;

并在我的实现中使用它:

LocalDateTime localDate = LocalDateTime.now(clock);

在测试方面我模拟了时钟

private final static LocalDate WEEKEND = LocalDate.of(2020, 07, 05);

@Mock
private Clock clock;
private Clock fixedClock;

并将其用作:

MockitoAnnotations.initMocks(this);

//tell your tests to return the specified LOCAL_DATE when calling LocalDate.now(clock)
fixedClock = Clock.fixed(WEEKEND.atTime(9, 5).toInstant(ZoneOffset.UTC), ZoneId.of("CET"));
doReturn(fixedClock.instant()).when(clock).instant();
doReturn(fixedClock.getZone()).when(clock).getZone();

ResponseEntity<String> response = restTemplate.postForEntity(base.toString(), request, String.class);

当我调试它时,fixedClock 具有我预期的值 FixedClock[2020-07-05T09:05:00Z,CET]。相反,如果我在服务实现上放置断点,localDate 变量的值为 2020-07-09 - .now()

我的问题是:为什么 localDate 变量没有 fixedClock 变量的值?

非常感谢您的宝贵时间!

稍后编辑:

这是服务的构造函数:

@Autowired
public SavingAccountService(
SavingAccountRepository savingAccountRepository, UserRepository userRepository, Clock clock) {
this.savingAccountRepository = savingAccountRepository;
this.userRepository = userRepository;
this.clock = clock;
}

我的 TestClass 上的注释:

RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = ChallengeApplication.class)
@ActiveProfiles("test")
public class SavingAccountTest {

@Mock
private Clock clock;
private Clock fixedClock;

@InjectMocks
private SavingAccountService savingAccountService;

@Autowired
private TestRestTemplate restTemplate;
private URL base;

@LocalServerPort
int port;

我还想提一下,在我的测试中,我调用的是 Controller 而不是服务。

private final SavingAccountService savingAccountService;   

public SavingAccountRestController(SavingAccountService savingAccountService) {
this.savingAccountService = savingAccountService;
}

@Override
@PostMapping
public ResponseEntity<?> newSavingAccount(@RequestBody SavingAccount savingAccount) {
EntityModel<SavingAccount> newSavingAccount = savingAccountService.newSavingAccount(savingAccount);
return new ResponseEntity<>(newSavingAccount, HttpStatus.CREATED);
}

最佳答案

问题

您在测试中创建了一个使用注入(inject)模拟的 SavingAccountService。

@InjectMocks
private SavingAccountService savingAccountService;

问题是这不是您的 Controller 使用的服务。Spring boot 测试创建应用程序上下文中定义的 bean, Autowiring 它们,并愉快地忽略测试中定义的服务的存在。

解决方案

你必须让 Spring boot 知道固定时间的 Clock bean

选项 1:模拟 bean

你来定义

@MockBean
private Clock clock;
private Clock fixedClock;

你应该可以开始了。

我仍然觉得这个方法很复杂,我想将固定时钟作为 bean 传递给 Spring Boot 上下文,而不是创建模拟。

选项 2:指定用于加载 ApplicationContext 的组件类。

在你的测试目录中创建一个新的配置类

@Configuration
public class FakeClockConfig {

private final static LocalDate WEEKEND = LocalDate.of(2020, 07, 05);

@Bean
public Clock clock() {
return Clock.fixed(WEEKEND.atTime(9, 5).toInstant(ZoneOffset.UTC), ZoneId.of("CET"));
}
}

让 Spring Boot 测试知道这个额外的配置

@SpringBootTest(webEnvironment = RANDOM_PORT, 
classes = {ChallengeApplication.class, FakeClockConfig.class})

我觉得这种方法更可取,你已经自己指定了一个组件类。

恒定时钟将取代您原来的时钟

选项 3:@TestConfiguration

参见 Spring boot – @TestConfiguration

@TestConfiguration is specialized form of @Configuration that can be used to define additional beans or customizations for a test.

In spring boot, any beans configured in a top-level class annotated with @TestConfiguration will not be picked up via component scanning. We must explicitly register the @TestConfiguration class with the class that contains the test cases.

There are two ways to include this additional test configuration for tests:

1.1. @Import annotation

1.2. Static nested classes

让我们采用后一种方法:

@SpringBootTest(properties = "spring.main.allow-bean-definition-overriding=true")
public class ProjetRepositoryTest {

private static final LocalDate WEEKEND = LocalDate.of(2020, 07, 05);

@TestConfiguration
static class FakeClockConfig {

@Bean
public Clock clock() {
return Clock.fixed(WEEKEND.atTime(9, 5).toInstant(ZoneOffset.UTC), ZoneId.of("CET"));
}
}
}

请注意,此方法会创建额外的 bean,因此我需要允许覆盖 bean。

参见 Spring-Boot 2.1.x and overriding bean definition

其他备注

您似乎正在使用 TestRestTemplate 进行后端测试。您可能更喜欢使用 MockMvc。

参见 Difference between MockMvc and RestTemplate in integration tests

关于java - 使用 Clock.fixed() 模拟 LocalDate.now(clock),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62817126/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com