Testing date based business logic is hard, since Spring is now based on Java 8 its possible to use java.time.Clock and mutable clock from Three Ten Extra. It would be useful to include such a mutable clock in spring test context framework along with an injectable Clock that returns the default system clock. Below is code that implement this.

/**
 * A factory for obtaining an instance fo the java.util.clock that will be injected into by spring
 * into any components that require a clock to know the current time.
 */
public interface ClockProvider {
  Clock clock();
}
/** Default Clock provider for the application. It returns the same clock used by Instant.now() */
@Component
class DefaultClockProvider implements ClockProvider {

  @Override
  public Clock clock() {
    return Clock.systemUTC();
  }
}

notice that I have to use @Primary and @TestFixtureComponent on my test fixture implementation that provides a jsr 310 extras mutable clock.

@Primary
@TestFixtureComponent
class TestClockProvider implements ClockProvider {
  private final Logger logger = LoggerFactory.getLogger(TestClockProvider.class);

  @PostConstruct
  void init() {
    logger.warn("** ++ TestClockProvider with a Mutable Clock In Use ++ **");
  }

  @Override
  public Clock clock() {
    return MutableClock.of(Instant.now(), ZoneOffset.UTC);
  }
}

There is also a @Configuration class to create a Clock Bean so that my code can just inject a java.util.Clock where it needs to know the current time. This class is in src/main/java

@Configuration
class ClockConfig {
  @Bean
  Clock clock(ClockProvider clockProvider) {
    return clockProvider.clock();
  }
}

TimeMachine class below can be autowired into test classes and used to move the clock forwards, backwards ... etc.

@TestFixtureComponent
@ConditionalOnBean(TestClockProvider.class)
public class TimeMachine {
  private final MutableClock clock;

  public TimeMachine(Clock clock) {
    this.clock = (MutableClock) clock;
  }

  /**
   * Advanced the clock used by the application by a certain number of seconds.
   *
   * @param seconds the number of seconds to advance the clock by
   */
  public void advanceSeconds(long seconds) {
    this.clock.add(Duration.ofSeconds(seconds));
  }
}

A lot of business logic does date and time comparisons injection of a clock is the recommended way to do this in Java 8 and above. Adding Spring support for virtual clock is quite useful.

Comment From: sbrannen

Why do you need the ClockProvider API?

Why not just register a Clock bean directly in the ApplicationContext and simply override it in test config with a mutable variant?

Comment From: asaikali

I can't remember why I needed the ClockProvider I will try to remove it and see if I can remember the real reason why. When I was writing this code, I was also learning how to use gradle, junit5 features, figuring out the design of what I am building ... etc so could be a good refactoring.

Below is my guess as to why I did it that way.

I started out with beans defined via @Bean on @Configuration then I decided that I really don't like writing useless code. So I switched to @Component scanning with constructor injection. Some of my src/test classes contain samples using @SpringBootApplication applications that explore how a user would use a collection of classes outside of a test case scenario, so I wanted to see in the log warnings when I was using any kind of replacement test fixtures, in case my CI failed and i needed to investigate, @PostConstruct seemed like a good way to do things.

@PostConstruct
  void init() {
    logger.warn("** ++ TestClockProvider with a Mutable Clock In Use ++ **");
  }

Comment From: sbrannen

Team Decision: the core Spring Framework team feels that it is best for applications to simply declare a Clock bean in the ApplicationContext and then override that bean in testing scenarios -- for example with bean definition profiles and/or the use of @Primary.

In light of that, I am closing this issue.

As a side note, the logging you have introduced could also be implemented directly in the @Bean method that configures the mutable Clock implementation or, if you prefer, in a @PostConstruct method in the @Configuration class that declares that @Bean method.