简体   繁体   中英

Unable to Mock System.currentTimeMillis()

I am writing unit tests using TestNG. The problem is when I mock System.currentTimeMillis, it returns the actual value instead of the mocked one. Ideally, it should return 0L, but it returns the actual value. What should I do to proceed?

class MyClass{

    public void func1(){
       System.out.println("Inside func1");
       func2();
    }

    private void func2(){
        int maxWaitTime = (int)TimeUnit.MINUTES.toMillis(10);
        long endTime = System.currentTimeMillis() + maxWaitTime; // Mocking not happening
        while(System.currentTimeMillis() <= endTime) {
                System.out.println("Inside func2");
        }
    }
}

@PrepareForTest(System.class)
class MyClassTest extends PowerMockTestCase{
   private MyClass myClass;
   
   @BeforeMethod
   public void setup() {
     MockitoAnnotations.initMocks(this);
     myclass = new MyClass();
   }
   @Test    
   public void func1Test(){
      PowerMockito.mockStatic(System.class)
      PowerMockito.when(System.currentTimeMillis()).thenReturn(0L);
      myclass.func1();
   }
}

Make a package constructor that you can pass in a java.time.Clock

class MyClass{ 
    private Clock clock;
    public MyClass() {
        this.clock = Clock.systemUTC();
    } 
    // for tests 
    MyClass(Clock c) {
        this.clock = c;
   } 

Then mock that for tests, and use this.clock.instant() to get the clock's time

You need to add the annotation @RunWith(PowerMockRunner.class) to the class MyClassTest .

Nevertheless, I would advise to refactor the code to use java.time.Clock , instead of mocking.

Instead of using PowerMock , you can use Mockito which also has a mockStatic method

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.9.0</version>
    <scope>test</scope>
</dependency>

See this answer for an example with LocalDate

Here is how it would look like in your case

try(MockedStatic<System> mock = Mockito.mockStatic(System.class, Mockito.CALLS_REAL_METHODS)) {
    doReturn(0L).when(mock).currentTimeMillis();
    // Put the execution of the test inside of the try, otherwise it won't work
}

Notice the usage of Mockito.CALLS_REAL_METHODS which will guarantee that whenever System is invoked with another method, it will execute the real method of the class

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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