-3

I have a java method and I want to somehow mock the system clock for testing purposes, so I can have that method return the result of what it would after 1 minute. I do now want to use a thread and block the time for a minute so instead was wondering if I can fake the time and assume 1 minute already passed.

More specifically, I have a method which runs every 1 minute and I want to test if it was invoked twice after 2 minutes.

manzk
  • 586
  • 1
  • 4
  • 11
  • 2
    Check if https://stackoverflow.com/questions/5622194/time-dependent-unit-tests?noredirect=1&lq=1 answers your question. In Java8 you can use java.time.Clock. – lugiorgi Jan 21 '20 at 10:17
  • It is not very clear. I tried to look at the library but I dont see how it is setting the fake time – manzk Jan 21 '20 at 10:21
  • I don't know which methods you use but assuming that you use Instant.now().getEpochSecond(), you can refactor your code to inject a Clock and use Instant.now(clock).getEpochSecond() instead. Then in your test you can pass a mocked Clock instance and define the behaviour. – lugiorgi Jan 21 '20 at 10:26

1 Answers1

0

Rewrite your code to not using System.currentTimeMillis() directly (or anything you are using) but to make it possible to inject your own time provider. Then you can easily mock this provider inside your test

public class YourService {
    public YourService(Supplier<Long> timeSupplier) { // use it like e.g. new YourService(System::currentTimeMillis)
        // ...
    }
}

class TimeSupplierMock {
    private long time; // add getters and setter

    TimeSupplierMock(long time) {
        this.time = time;
    }
}


class MyTest {
    @Test
    public void test() {
        TimeSupplierMock mock = new TimeSupplierMock(0);
        YourService service = new YourService(mock);

        // ...

        mock.setTime(20); // increasing time

}
m.antkowicz
  • 13,268
  • 18
  • 37
  • 1
    I would be thankful for short explanation why `-1` ;) – m.antkowicz Jan 21 '20 at 10:27
  • Because nobody in their right mind will be writing their own "time provider". They'll be using either JodaTime, `java.time` (both of which provide ways to adjust the time), or if they're working with legacy code (at which point they won't be writing any tests), `java.util.Calendar`. No reason to overengineer. – Kayaman Jan 21 '20 at 10:29
  • Yeah and I even gave an example how to provide such `System` feature - the Yoda one you can provide exactly the same by method reference - you don't need and you shouldn't write your own one. The only place where you should provide your own implementation is testing class to not dirty hack JVM to fake time or... wait 20 seconds :) It's not overengineering it's named 'dependency injection' – m.antkowicz Jan 21 '20 at 10:33
  • I meant that your answer is overengineering, because you're providing an additional unnecessary abstraction layer. You don't need a `TimeSupplier`, you need to look at which calendar implementation you're using, and then use the tools provided by that. I'm sure you feel quite smart for talking about "dependency injection" (welcome to 5 years ago), but your answer is "unnecessary code". – Kayaman Jan 21 '20 at 10:37
  • Just take a look what Joda provides you to make as you would like to - some dirty hack, that freezing time, adding some offset, then you need to unfreeze this manually - if you will forget it's disaster. What if you will use another tool that don't have such methods or many tools in many places? What if they affects whole JVM? **If time depending is critical** (and here it is because why OP would like to test this?) for such method/system extracting this to another level is not overengineering for me - it gives you all pros of using dependency injection and costs nothing – m.antkowicz Jan 21 '20 at 10:49
  • @m.antkowicz thanks for your response. It is not exactly what I am looking for but I see your logic so I gave you an up vote :) – manzk Jan 21 '20 at 11:09
  • I know how Joda's tools work (which means you better known how to write your tests properly), and of course it's better not to write time dependent tests anyway (there's no guarantee that OP *needs* to do it, people try to write bad tests here all the time). I'm saying that your solution is nowhere near as clever as you think it is. – Kayaman Jan 21 '20 at 11:12