In mijn testcase heb ik een testtijdgevoelige methode nodig, in die methode gebruiken we java 8-klasse LocalDate, het is niet Joda.
Wat kan ik doen om de tijd te veranderen als ik een test doe
Antwoord 1, autoriteit 100%
Vervang in uw code LocalDate.now()
door LocalDate.now(clock);
.
U kunt dan Clock.systemDefaultZone()
doorgeven voor productie en een vaste klokom te testen.
Dit is een voorbeeld:
Injecteer eerst de Clock
. Als je springboot gebruikt, doe dan gewoon een:
@Bean
public Clock clock() {
return Clock.systemDefaultZone();
}
Ten tweede, bel LocalDate.now(clock)
in uw code :
@Component
public class SomeClass{
@Autowired
private Clock clock;
public LocalDate someMethod(){
return LocalDate.now(clock);
}
}
Nu, binnen je unit-testklasse:
// 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);
}
Antwoord 2, autoriteit 3%
Je kunt je code herstructureren om het testvriendelijk te maken, bijvoorbeeld door alle aanroepen van LocalDate.now()
te vervangen door een methode van een aangepaste mockable niet-statische klasse.
Als alternatief kunt u mockStatic van PowerMockgebruiken.
Antwoord 3, autoriteit 2%
Als we statische methoden zoals now() moeten bespotten, kunnen we meerdere alternatieven gebruiken, zoals 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);
}
}
Of JMockit, inderdaad met JMockit kunnen we de MockUp-klasse gebruiken:
@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);
}
Of de klasse Verwachtingen:
@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 kunnen hiermeer voorbeelden vinden.
Een ander eenvoudig alternatief is het gebruik van de now()methode met een vaste Clock-instantie. Zeker, de meeste klassen in het java.time-pakket hebben een now()-methode met een 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);
}
Antwoord 4
Misschien wilt u ook een vaste klok in productie doorgeven (waarvan de waarde wordt vastgesteld aan het begin van een transactie) om te voorkomen dat u inconsistent “nu” gebruikt in verschillende entiteiten en verzoeken.
Zie deze vraagvoor details.
Antwoord 5
We moeten hier een statische methode bespotten. Ik gebruik de volgende afhankelijkheid. Onthoud dat al onze testcode in het try-blok moet staan. Zodra we LocalDate.now() of LocalDate
. aanroepen
<!-- 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>
De 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));
}
}
Antwoord 6
Lente gebruiken:
ClockConfiguration-klasse:
@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-klasse:
@Service
@RequiredArgsConstructor
public class SomeService {
private final Clock clock;
public void someMethod(){
...
LocalDateTime.now(clock)
LocalDate.now(clock)
...
}
}
U moet een actief “test”-profiel hebben in de test:
SomeServiceTest-klasse:
@ActiveProfiles("test")
@EnableConfigurationProperties
@SpringBootTest(classes = [YourAppMainClass])
class SomeServiceTest {
...
}
Antwoord 7
Je kunt de leverancier binnen je klas die je aan het testen bent, gebruiken om de huidige tijd te halen, waar de datum-tijd ook wordt gebruikt.
public Supplier<LocalDateTime> localDateTime = () -> LocalDateTime.now();
en in de testmethode overschrijf je gewoon de waarde zoals :
myClassObj.localDateTime = () -> LocalDateTime.parse("2020-11-24T23:59:59.999");
Antwoord 8
Je kunt de huidige datum gewoon als functieparameter doorgeven.
fun doSmthng(now: LocalDate = LocalDate.now()) {
testAnotherService.doSmthng1(TestObj("my message!", now))
}
En in de test kun je een specifieke datum doorgeven en erop beweren. Het idee is om de afhankelijkheden te injecteren in plaats van expliciet te creëren in de hoofdtekst van de functie.