richersoon
richersoon

Reputation: 4902

How to Mock only LocalDate.now() using PowerMock

I want to mock only the now() of LocalDate using PowerMock. It seems that it's ignoring the thenReturn value:

java.lang.AssertionError: 
Expected :2008
Actual   :2017

Test setup:

@PrepareForTest(LocalDate.class)
@RunWith(PowerMockRunner.class)
public class UserTest {

    @Test
    public void nowShouldReturnSameYear() throws Exception {
        LocalDate expected = LocalDate.parse("2008-04-04");

        PowerMockito.spy(LocalDate.class);
        when(LocalDate.now()).thenReturn(expected);

        Foo foo = new Foo();
        assertEquals(expected.getYear(), foo.getRightNow().getYear());
    }

Foo.java

public LocalDate getRightNow(){
        final LocalDate rightNow = LocalDate.now();
        return rightNow;
    }

Upvotes: 7

Views: 8698

Answers (1)

user7605325
user7605325

Reputation:

You should PrepareForTest the Foo class:

@PrepareForTest(Foo.class)
@RunWith(PowerMockRunner.class)
public class ...

I'm not sure how spy behaves for static methods, so I prefer to use mockStatic:

PowerMockito.mockStatic(LocalDate.class);
when(LocalDate.now())....

To make the code more testable and don't depend on mocking static methods, you could also refactor your code to use a java.time.Clock:

public class Foo {

    private Clock clock;

    public Foo() {
        // use the system's default clock
        this(Clock.systemDefaultZone());
    }

    public Foo(Clock clock) {
        // use a custom clock
        this.clock = clock;
    }

    public LocalDate getRightNow() {
        final LocalDate rightNow = LocalDate.now(this.clock);
        return rightNow;
    }
}

If you don't specify a Clock, it'll use the system's default (exactly what the now() method does when called without parameters).

Then, in your test, you create a Clock that always return the same date and pass it to the Foo class. In this case, you won't need all the PowerMockito stuff:

public class UserTest {

    @Test
    public void nowShouldReturnSameYear() throws Exception {
        LocalDate parse = LocalDate.parse("2008-04-04");
        // create a fixed clock (it always return the same date, using the system's default timezone)
        ZoneId zone = ZoneId.systemDefault();
        Clock clock = Clock.fixed(parse.atStartOfDay(zone).toInstant(), zone);

        Foo foo = new Foo(clock);
        assertEquals(parse.getYear(), foo.getRightNow().getYear());
    }
}

Upvotes: 9

Related Questions