3

I have a spring boot configuration class like this:

@Configuration
public class ClockConfiguration {

    @Bean
    public Clock getSystemClock() {
        return Clock.systemUTC();
    }
}

and I have some integration tests like this:

@SpringBootTest(classes = MyApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public abstract class AbstractIntegrationTest  {

}

and tests like this:

public class MiscTests extends AbstractIntegrationTest{

    @Test
    public void CreateSomethingThatOnlyWorksInThe Morning_ExpectCorrectResponse() {

    }

I want to be able to offset the clock bean to run some tests at different times on the day. How do I do this?

NOTE: I see several stack overflow answers similar to this, but I can't get them to work.

Based on other responses, it appears the solution should be something like:

@SpringBootTest(classes = MyApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public abstract class AbstractIntegrationTest  {

    @Configuration
    class MyTestConfiguration {

        @Bean
        public Clock getSystemClock() {
            Clock realClock = Clock.systemDefaultZone();
            return Clock.offset(realClock, Duration.ofHours(9));
        }
    }
}

But nothing happens there. Do I need to @Import something? do I need to @Autowired something?

Thanks!

user952342
  • 2,602
  • 7
  • 34
  • 54

2 Answers2

2

As you are using Spring Boot you can take advantage of the @MockBean annotation:

@SpringBootTest(classes = MyApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT)
public abstract class AbstractIntegrationTest  {

    @MockBean
    private Clock clockMock;
}

Then you can stub public methods of that bean an each of the tests accordingly and uniquely:

@Test
public void CreateSomethingThatOnlyWorksInThe Morning_ExpectCorrectResponse() {
     when(clockMock.getTime()).thenReturn(..);
}

As per javadoc of @MockBean:

Any existing single bean of the same type defined in the context will be replaced by the mock.

Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
  • hmm, I'm confused. When you say: {at}MockBean private Clock clockMock; did you mean: {at}MockBean public ClockConfiguration mockClock; keeping in mind, the class I want to override (or mock) is called "ClockConfiguration". Anyhow, when I add what I think you meant, I get this error: "java.lang.IllegalStateException: Failed to load ApplicationContext" – user952342 Jun 18 '19 at 18:50
  • @user952342 you cant overtide configuration with mock framework. To override configuration you need Testconfiguration . If you use Mock you need to Mock the Clock, not the configuration. – Alexander Petrov Jun 21 '19 at 05:19
0

it is the @TestConfiguration annotation that you need https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/TestConfiguration.html

@RunWith(SpringRunner.class)
public class ClockServiceImplIntegrationTest {

    @TestConfiguration
    static class TestOverridingClockServiceConfiguration {

        @Bean
        public ClockService clockService() {
            return new ClockServiceImpl();
        }
    }

    @Autowired
    private ClockService clockService;

    @MockBean
    private ClockRepository clockRepository;

    // write test cases here
}

In the case you have existing configuration you c

Alexander Petrov
  • 9,204
  • 31
  • 70