Neil
Neil

Reputation: 3056

How can I mock java.time.LocalDate.now()

In my test case, I need test time sensitive method, in that method we're using java 8 class LocalDate, it is not Joda.

What can I do to change time, when I'm running test

Upvotes: 113

Views: 157301

Answers (11)

tahirhasanov
tahirhasanov

Reputation: 21

if you need this mocking only for test coverage, you can use any() instead of LocalDateTime.now(). Otherwise, look another comments.

Upvotes: 0

vesper
vesper

Reputation: 87

given i have a random class with a method that just returns LocalDate.now()

import java.time.LocalDate;

public RandomClass {

    public LocalDate getTodaysDate() {
        return LocalDate.now();
    }
}

and i want to mock that to return my birthday instead

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;

import java.time.LocalDate;
import java.time.Month;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class RandomClassTest {

    private RandomClass randomClass;

    private MockedStatic<LocalDate> localDateMockedStatic;

    @BeforeEach
    void setUp() {
        randomClass = new RandomClass();

        // instead of using try-with resources, i decide to initialize the mockedStatic object before each test method
        localDateMockedStatic = Mockito.mockStatic(LocalDate.class, Mockito.CALLS_REAL_METHODS);
    }

    @AfterEach
    void tearDown() {
        localDateMockedStatic.reset();        
        localDateMockedStatic.close(); // and close the mockedStatic after each test method
    }

    @Test
    public void getTodaysDateBirthdayTest() {
        LocalDate birthday = LocalDate.of(1999, Month.SEPTEMBER, 29);

        localDateMockedStatic.when(LocalDate::now).thenReturn(birthday);

        assertEquals(birthday, randomClass.getTodaysDate());
    }

    @Test
    public void getTodaysDateDefaultTest() {
        // due to Mockito.CALLS_REAL_METHODS, this has default functionality
        assertEquals(LocalDate.now(), randomClass.getTodaysDate());
    }
}

this is essentially the same thing as some other responses in this thread but this just looks more visually pleasant to me so this is how i like to do it

Upvotes: 0

Aayush Bhattacharya
Aayush Bhattacharya

Reputation: 1934

to Mock LocalDate to desired date

    @Test
    public void mockStaticMethod() {
        //dummy data
        try(MockedStatic<LocalDate> mockedStatic=Mockito.mockStatic(LocalDate.class,Mockito.CALLS_REAL_METHODS)){
            LocalDate currentDate=LocalDate.of(2023, 1, 11);
            mockedStatic.when(LocalDate::now).thenReturn(currentDate);
          //yourService.serviceMethod(arguments);
          //assertEquals(expected, actual);
        }
    }

Upvotes: 2

Beast77
Beast77

Reputation: 223

If you are here and using Mockito and Kotlin, do the following:

        mockStatic(LocalDate::class.java, Mockito.CALLS_REAL_METHODS).use {
        `when`(LocalDate.now()).thenReturn(date)
        // Do your stuff here
    }

If you are using Java, check out this issue for how it is done.

Upvotes: 3

TheLittleChimp
TheLittleChimp

Reputation: 31

You can mock final classes with Mockito. Add this 'mockito-extensions' directory to your src/test/resources i.e. src/test/resources/mockito-extensions

Add this file

org.mockito.plugins.MockMaker

with content

mock-maker-inline

Mockito will check the extensions directory for configuration files when it is loaded. This file will enable the mocking of final methods and classes.

You can find more details on this approach using baeldung

Another programmatic approach is using MockMakers.INLINE in your code as shown in the official example:

Mockito.mock(ClassWithFinalMethod.class, withSettings().mockMaker(MockMakers.INLINE));
Mockito.when(inlineMock.finalMethodCallingNonFinal()).thenReturn("MOCKED");
assertEquals("MOCKED", inlineMock.finalMethodCallingNonFinal());

You can also use annotation as described in the docs:

@Mock(mockMaker = MockMakers.INLINE)
Foo mock;

Upvotes: 1

user2420898
user2420898

Reputation: 149

We have to mock a static method here. I use following dependency. Remember all our test code has to be in the try block. As soon as we call LocalDate.now() or LocalDate

<!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>3.11.0</version>
    <scope>test</scope>
</dependency>

The code:

 @Test
    void verifykNonLeapYear() {

        LocalDate currentLocalDate = LocalDate.of(2010, 2, 13);
        try (MockedStatic<LocalDate> topDateTimeUtilMock = Mockito.mockStatic(LocalDate.class)) {
            topDateTimeUtilMock.when(() -> LocalDate.now()).thenReturn(currentLocalDate);
            assertThat(TopDateTimeUtil.numberOfDaysInCurrentYear(), is(365));
        }
    }

Upvotes: 13

Ghanshyam Parmar
Ghanshyam Parmar

Reputation: 31

You can use supplier inside your class which you are testing to pass current time wherever date time is used.

public Supplier<LocalDateTime> localDateTime = () -> LocalDateTime.now();

and in the test method just override its value like :

myClassObj.localDateTime = () -> LocalDateTime.parse("2020-11-24T23:59:59.999");

Upvotes: 3

assylias
assylias

Reputation: 328649

In your code, replace LocalDate.now() with LocalDate.now(clock);.

You can then pass Clock.systemDefaultZone() for production and a fixed clock for testing.


This is an example :

First, inject the Clock. If you are using spring boot just do a :

@Bean
public Clock clock() {
    return Clock.systemDefaultZone();
}

Second, call LocalDate.now(clock) in your code :

@Component
public class SomeClass{

    @Autowired
    private Clock clock;

    public LocalDate someMethod(){
         return LocalDate.now(clock);
    }
}

Now, inside your unit test class :

// Some fixed date to make your tests
private final static LocalDate LOCAL_DATE = LocalDate.of(1989, 01, 13);

// mock your tested class
@InjectMocks
private SomeClass someClass;

//Mock your clock bean
@Mock
private Clock clock;

//field that will contain the fixed clock
private Clock fixedClock;


@Before
public void initMocks() {
    MockitoAnnotations.initMocks(this);

    //tell your tests to return the specified LOCAL_DATE when calling LocalDate.now(clock)
    fixedClock = Clock.fixed(LOCAL_DATE.atStartOfDay(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault());
    doReturn(fixedClock.instant()).when(clock).instant();
    doReturn(fixedClock.getZone()).when(clock).getZone();
}

@Test
public void testSomeMethod(){
    // call the method to test
    LocalDate returnedLocalDate = someClass.someMethod();

    //assert
    assertEquals(LOCAL_DATE, returnedLocalDate);
}

Upvotes: 181

Strax
Strax

Reputation: 111

Using Spring:

ClockConfiguration class:

@Configuration
public class ClockConfiguration {
    private final static LocalDate LOCAL_DATE = LocalDate.of(2019, 12, 17);

    @Bean
    @ConditionalOnMissingBean
    Clock getSystemDefaultZoneClock() {
        return Clock.systemDefaultZone();
    }

    @Bean
    @Profile("test")
    @Primary
    Clock getFixedClock() {
        return Clock.fixed(LOCAL_DATE.atStartOfDay(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault());
    }
}

SomeService class:

@Service
@RequiredArgsConstructor
public class SomeService {

    private final Clock clock;

    public void someMethod(){
        ...

        LocalDateTime.now(clock)
        LocalDate.now(clock)

        ...
    }
}

You must have an active "test" profile in the test:

SomeServiceTest class:

@ActiveProfiles("test")
@EnableConfigurationProperties
@SpringBootTest(classes = [YourAppMainClass])
class SomeServiceTest {
    ...
}

Upvotes: 0

Juan Moreno
Juan Moreno

Reputation: 2785

If we need to mock static methods like now() we can use multiple alternatives like PowerMock:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ LocalDateTime.class })
public class LocalDateTimeUnitTest {

    @Test
    public void givenLocalDateTimeMock_whenNow_thenGetFixedLocalDateTime() {
        Clock clock = Clock.fixed(Instant.parse("2014-12-22T10:15:30.00Z"), ZoneId.of("UTC"));
        LocalDateTime dateTime = LocalDateTime.now(clock);
        mockStatic(LocalDateTime.class);
        when(LocalDateTime.now()).thenReturn(dateTime);
        String dateTimeExpected = "2014-12-22T10:15:30";

        LocalDateTime now = LocalDateTime.now();

        assertThat(now).isEqualTo(dateTimeExpected);
    }
}

Or JMockit, indeed with JMockit we can use the MockUp class:

@Test
public void givenLocalDateTimeWithJMock_whenNow_thenGetFixedLocalDateTime() {
    Clock clock = Clock.fixed(Instant.parse("2014-12-21T10:15:30.00Z"), ZoneId.of("UTC"));
    new MockUp<LocalDateTime>() {
        @Mock
        public LocalDateTime now() {
            return LocalDateTime.now(clock);
        }
    };
    String dateTimeExpected = "2014-12-21T10:15:30";

    LocalDateTime now = LocalDateTime.now();

    assertThat(now).isEqualTo(dateTimeExpected);
}

Or the Expectations class:

@Test
public void givenLocalDateTimeWithExpectations_whenNow_thenGetFixedLocalDateTime() {
    Clock clock = Clock.fixed(Instant.parse("2014-12-23T10:15:30.00Z"), ZoneId.of("UTC"));
    LocalDateTime dateTimeExpected = LocalDateTime.now(clock);
    new Expectations(LocalDateTime.class) {
        {
            LocalDateTime.now();
            result = dateTimeExpected;
        }
    };

    LocalDateTime now = LocalDateTime.now();

    assertThat(now).isEqualTo(dateTimeExpected);
}

We can find more examples here.

Another simple alternative is to use the now() method with a fixed Clock instance. Certainly, most of the classes in java.time package have a now() method with a Clock parameter:

@Test
public void givenFixedClock_whenNow_thenGetFixedLocalDateTime() {
    Clock clock = Clock.fixed(Instant.parse("2014-12-22T10:15:30.00Z"), ZoneId.of("UTC"));
    String dateTimeExpected = "2014-12-22T10:15:30";

    LocalDateTime dateTime = LocalDateTime.now(clock);

    assertThat(dateTime).isEqualTo(dateTimeExpected);
}

Upvotes: 4

Aivean
Aivean

Reputation: 10882

You can refactor you code to make it test-friendly, for example, replace all invocations of LocalDate.now() with invocation of some method of custom mockable non-static class.

Alternatively, you can use PowerMock's mockStatic.

Upvotes: 12

Related Questions