如何在Spring中将java.time.Clock抽象出来进行测试

如何在Spring中将java.time.Clock抽象出来进行测试,java,spring,junit,jsr310,Java,Spring,Junit,Jsr310,关于这个问题,我有一个问题 假设我构建了包含服务接口及其实现的Spring应用程序 如果我想在测试中更改时钟,我将不得不“污染”生产代码,并与例如setClock方法接口,如下所示: public interface MyService { void heavyBusinessLogic(); void setClock(Clock clock); } @Service public class MyServiceImpl implements MyService {

关于这个问题,我有一个问题

假设我构建了包含服务接口及其实现的Spring应用程序

如果我想在测试中更改时钟,我将不得不“污染”生产代码,并与例如
setClock
方法接口,如下所示:

public interface MyService {
    void heavyBusinessLogic();
    void setClock(Clock clock);
}

@Service
public class MyServiceImpl implements MyService {

    private Clock clock = Clock.systemDefaultZone();

    @Override
    public void heavyBusinessLogic() {
        if (LocalDate.now(clock)...) {
            ... 
        }
    }

    @Override
    public void setClock(Clock clock) {
        this.clock = clock;
    }
}   
在测试中,我可以调用,例如:

service.setClock(Clock.fixed(Instant.parse("2017-02-14T01:22:00Z"), ZoneOffset.UTC));
我怎样才能在春天摆脱这种交叉关注呢


我想坚持使用java.time.Clock(我不想使用Joda)

就我个人而言,我只想在构造函数中添加时钟

public MyServiceImpl(Clock clock) {
  this.clock = clock;
}
public MyServiceImpl() {
  this(Clock.systemDefaultZone());
}
…也许还可以添加一个不错的默认构造函数

public MyServiceImpl(Clock clock) {
  this.clock = clock;
}
public MyServiceImpl() {
  this(Clock.systemDefaultZone());
}
通过这种方式,您可以通过spring获得默认值,并手动创建自定义时钟版本,例如在测试中

当然,您也可以放弃默认构造函数,只需在生产配置中添加一个
Clock
bean,例如

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

…它允许您在测试配置中使用模拟的
时钟作为bean,自动允许Spring通过构造函数注入
@Autowire
它。

时钟建模的好方法是使用
ThreadLocal
,特别是当您在JPA实体中需要它时,例如:

@Entity
public class MyEntity {
   public static final ThreadLocal<Clock> CLOCK =
            ThreadLocal.withInitial(Clock::systemDefaultZone);
}
@实体
公共类MyEntity{
公共静态本地时钟=
ThreadLocal.withInitial(时钟::systemDefaultZone);
}

为什么不改用构造函数注入?那么在interfacejava.time.Clock中就没有
setClock()
方法了……这不是问题,因为您可以在生产配置中定义一个时钟bean,在测试配置中定义一个模拟的时钟bean……我刚刚遇到另一个问题。我想在实体本身中使用时钟进行时间敏感的比较,我认为注入时钟bean不是一个好主意。你有什么建议?为什么你认为这不是个好主意?我不太明白这有什么问题……它需要aspectj加载时编织或Hibernate LoadEventListener。我认为有一种更标准的方法可以做到这一点:)