5

One can use Clock to mock calls like System.currentTimeMillis() using Clock.millis() and injecting a mock implementation of Clock.

Is there a similar way to easily mock System.nanoTime()?

Brandon E Taylor
  • 24,881
  • 6
  • 47
  • 71
  • https://stackoverflow.com/questions/20689055/java-8-instant-now-with-nanosecond-resolution#:~:text=While%20default%20Java8%20clock%20does%20not%20provide%20nanoseconds%20resolution%2C%20you%20can%20combine%20it%20with%20Java%20ability%20to%20measure%20time%20differences%20with%20nanoseconds%20resolution%2C%20thus%20creating%20an%20actual%20nanosecond%2Dcapable%20clock. – Oussama ZAGHDOUD Jun 20 '22 at 08:54

4 Answers4

2

Use your own encapsulation

interface NanoTimer {
  long nanoTime();
  static NanoTimer system() {
    return System::nanoTime;
  }
}

This way you can write your own mock very easily.

Alternatively, I can't see any use case besides a stopwatch, so I guess that you'd probably want to have a look at Guava's Stopwatch

Olivier Grégoire
  • 33,839
  • 23
  • 96
  • 137
1

You can use Google Guava's Ticker class that does exactly that.

Or, if you're simply trying to measure time properly, you can use Stopwatch for extra functionality and nicer API, its constructor takes a Ticker instance.

There's even a FakeTicker in guava-testlib if you find any of the other utilities in there useful. Otherwise writing a fake Ticker is obviously very easy.

Petr Janeček
  • 37,768
  • 12
  • 121
  • 145
1

You can use a interface for dependency injection during unit tests:

public class YourClass {
    private static TimeSupplier timeSupplier = System::nanoTime;

    @VisibleForTesting
    public static void setTimeSupplier(TimeSupplier timeSupplier) {
        YourClass.timeSupplier = timeSupplier;
    }

    @FunctionalInterface
    interface TimeSupplier {
        long nanoTime();
    }
    
    // Just use timeSupplier.nanoTime() instead of the static nanoTime calls
}

Then you can simply stub the timeout with a constant (Mockito for example):

YourClass.TimeSupplier timeSupplier = mock(YourClass.TimeSupplier.class);
when(timeSupplier.nanoTime()).thenReturn(20221116L);
YourClass.setTimeSupplier(timeSupplier);
Steven Chou
  • 1,504
  • 2
  • 21
  • 43
-2

Use Clock.instant(). According to documentation:

the class stores a long representing epoch-seconds and an int representing nanosecond-of-second

You can access the nano-part using Instant.getNano().

It's not equivalent, but it's analogous and it provides you with the same functionality. You even do not need to read the nano value, Instant represents the nano time. And you have arithmetical functions defined on the Instant class, such as minus(Instant), minusNanos(long) etc.

Honza Zidek
  • 9,204
  • 4
  • 72
  • 118
  • `Instant::getNano` gives only the nano part of the `Instant` instance, while `System::nanoTime` returns "the current value of the running Java Virtual Machine's high-resolution time source, in nanoseconds". That's not even roughly equivalent. – tquadrat Jun 20 '22 at 09:28
  • @tquadrat Of course it's not *equivalent*, it's **analogous**. You even do not need the nano value, `Instant` represents a nano time. And you have arithmetical functions defined on the `Instant` class, such as `minus(Instant)`, `minusNanos(long)` etc. – Honza Zidek Jun 20 '22 at 09:34
  • 2
    `System.nanoTime` uses monotonic clock, it can't go backwards, it won't slow down / speed up because of NTP. I do not know how to get that with Clock/Instant. – Petr Janeček Jun 20 '22 at 09:36
  • @PetrJaneček Of course it depends on your use case. If you are developing a real-time application and you are *critically* dependent on these properties, then you are right. Otherwise it's just academic. For **microbenchmarks**, you can never perform one measure only, you must run it many times and calculate the average, so rare fluctuations will not matter. – Honza Zidek Jun 20 '22 at 09:43
  • @HonzaZidek – It's not even analogous. But for a mock, equivalency is needed … – tquadrat Jun 20 '22 at 14:23