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
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
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);
}
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.
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));
}
}
MockedStatic<LocalDate> topDateTimeUtilMock = Mockito.mockStatic(LocalDate.class, Mockito.CALLS_REAL_METHODS);
This will make it so only the methods you specify will be mocked, everything else will work as normal –
Beamon 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);
}
LocalDateTime.now()
versus LocalDate.now()
I keep getting the "when() requires an argument which has to be 'a method call on a mock'." The powermock 2 beta does not seem to like LocalDate.now(). Does it matter that LocalDate is final? –
Thy mockStatic(LocalDateTime.class)
first?. There no difference between LocalDateTime and LocalDate (except for the return value), both are final classes. Which powermock version do you use? –
Limulus mockStatic(LocalDate.class)
first. I'm using PowerMock version 2.0.0-beta.5 –
Thy 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.
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");
You might also want to pass a fixed clock in production (the value of which is fixed at the start of a transaction) to avoid using inconsistent "now" in different entities and requests. See this question for details.
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;
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 {
...
}
@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);
}
}
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
© 2022 - 2024 — McMap. All rights reserved.