简体   繁体   English

如何在 Spring 中抽象出 java.time.Clock 用于测试目的

[英]How to abstract away java.time.Clock for testing purposes in Spring

I have a question with regards to the question Time dependent unit tests我对时间相关的单元测试问题有疑问

Let's say I build Spring application which contains service interface and its implementation假设我构建了包含服务接口及其实现的 Spring 应用程序

If I want to change clock in test, I would have to "pollute" production code and interface with eg setClock method as follows:如果我想在测试中更改时钟,我将不得不“污染”生产代码和接口,例如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;
    }
}   

In test, I can invoke, eg:在测试中,我可以调用,例如:

service.setClock(Clock.fixed(Instant.parse("2017-02-14T01:22:00Z"), ZoneOffset.UTC));

How can I abstract away such cross-cutting concern in Spring?我如何在 Spring 中抽象出这种横切关注点?

I want to stick with java.time.Clock (I don't want to use Joda)我想坚持使用 java.time.Clock(我不想使用 Joda)

Personally, I would simply add the clock in the constructor...就个人而言,我会简单地在构造函数中添加时钟......

public MyServiceImpl(Clock clock) {
  this.clock = clock;
}

...and perhaps add a nice default constructor... ...也许添加一个不错的默认构造函数...

public MyServiceImpl() {
  this(Clock.systemDefaultZone());
}

This way you can get the default thing via spring and create a custom clock version manually, for example in your tests.这样您就可以通过 spring 获取默认值并手动创建自定义时钟版本,例如在您的测试中。

Of course, you could also forgo the default constructor and simply add a Clock bean in your productive configuration, for example like this...当然,您也可以放弃默认构造函数并在您的生产配置中简单地添加一个Clock bean,例如像这样......

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

...which allows you to use a mocked Clock as a bean in your test configuration, automatically allowing Spring to @Autowire it via constructor injection. ...它允许您在测试配置中使用模拟Clock作为 bean,自动允许 Spring 通过构造函数注入@Autowire它。

Good way how to model clock is to use ThreadLocal , especially when you need it in JPA entity, eg:如何为时钟建模的好方法是使用ThreadLocal ,尤其是当您在 JPA 实体中需要它时,例如:

@Entity
public class MyEntity {
   public static final ThreadLocal<Clock> CLOCK =
            ThreadLocal.withInitial(Clock::systemDefaultZone);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM