Search code examples
javatestingmockitopowermock

How to mock Thread.sleep() with PowerMock?


How to mock Thread.sleep() with PowerMock?

Sample interface and class:

public interface Machine {

    void sleep(long millis);
}

public class MachineImpl
implements Machine {

    private static final Logger logger = Logger.getLogger(MachineImpl.class);

    @Override
    public void sleep(long millis) {
        try {
            if (millis > 0) {
                logger.trace(String.format("Try to sleep for %d millis...", millis));
                Thread.sleep(millis);
            }
        }
        catch (InterruptedException e) {
            logger.trace("Full exception", e);
        }
    }
}

Solution

  • This took me a while to figure out, so I am answering my own question.

    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.mockito.Mockito;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.junit4.PowerMockRunner;
    
    @RunWith(PowerMockRunner.class)  // important
    @PrepareForTest(MachineImpl.class)  // important: do not use Thread.class here
    public class MachineImplTest {
    
        private MachineImpl classUnderTest;
    
        @Before
        public void beforeEachTest() {
            classUnderTest = new MachineImpl();
        }
    
        @Test
        public void sleep_Pass() {
            classUnderTest.sleep(0);
            classUnderTest.sleep(-100);
            classUnderTest.sleep(+100);
        }
    
        @Test
        public void sleep_Pass2() {
            // We do not want to mock all methods, only specific methods, such as Thread.sleep().
            // Use spy() instead of mockStatic().
            PowerMockito.spy(Thread.class);
    
            // These two lines are tightly bound.
            PowerMockito.doThrow(new InterruptedException()).when(Thread.class);
            Thread.sleep(Mockito.anyLong());
    
            classUnderTest.sleep(0);
            classUnderTest.sleep(-100);
            classUnderTest.sleep(+100);
        }
    }
    

    If you are using TestNG, try this:

    import org.mockito.Mockito;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.core.classloader.annotations.PrepareForTest;
    import org.powermock.modules.testng.PowerMockTestCase;
    
    @PrepareForTest(MachineImpl.class)  // important: do not use Thread.class here
    public class MachineImplTest
    extends PowerMockTestCase {
        ...
    }
    

    Read more about TestNG + Mockito + PowerMock here: https://stackoverflow.com/a/35815153/257299