使用 PowerMockRunner 和 LocalDate class 模拟今天的日期
Using PowerMockRunner with LocalDate class to mock today's date
考虑如下使用 PowerMockRunner
:
的 DateUtilTest
class
import com.reporting.utils.DateUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.time.LocalDate;
import java.util.Date;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
@PrepareForTest(DateUtil.class)
@RunWith(PowerMockRunner.class)
public class DateUtilTest {
@Test
public void getPreviousWorkingDayAsDate_whenMonday() {
//given
LocalDate date = LocalDate.of(2017, 10, 16);
LocalDate expected = LocalDate.of(2017, 10, 13);
mockStatic(LocalDate.class);
when(LocalDate.now()).thenReturn(date);
//when
Date previousWorkingDay = DateUtil.getPreviousWorkingDayAsDate();
//then
assertEquals(DateUtil.getDateFromLocalDate(expected), previousWorkingDay);
}
@Test
public void getPreviousWorkingDayAsDate2_whenMonday() {
//given
LocalDate date = LocalDate.of(2017, 10, 16);
mockStatic(LocalDate.class);
when(LocalDate.now()).thenReturn(date);
//when
Date previousWorkingDay = DateUtil.getPreviousWorkingDayAsDate();
LocalDate expected = LocalDate.of(2017, 10, 13);
//then
assertEquals(DateUtil.getDateFromLocalDate(expected), previousWorkingDay);
}
}
我想了解为什么 @Test
==> getPreviousWorkingDayAsDate2_whenMonday
将 expected
LocalDate
初始化移动到 LocalDate.class
的模拟之后失败?
此外,这个测试是否可以改进?
另外,这个测试可以改进吗?
是 - 重构 DateUtil 以能够使用特定 Clock
。例如:
public class DateUtil {
private static Clock clock = Clock.systemDefaultZone();
public static setClock(Clock clock) {
assertNotProduction(); // optionally check for an environment/system variable to throw exception if used in production
DateUtil.clock = clock;
}
public static Date getPreviousWorkingDayAsDate() {
LocalDate today = LocalDate.now(clock); // use clock
...
return ...;
}
}
然后单元测试不需要任何模拟。例如:
@Test
public void getPreviousWorkingDayAsDate_whenMonday() {
//given
LocalDate monday = LocalDate.of(2017, 10, 16);
Clock clock = Clock.fixed(monday.atStartOfDay(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault());
DateUtil.setClock(clock);
LocalDate lastFriday = LocalDate.of(2017, 10, 13);
//when
Date previousWorkingDay = DateUtil.getPreviousWorkingDayAsDate();
//then
assertEquals(DateUtil.getDateFromLocalDate(lastFriday), previousWorkingDay);
}
@After
public void resetClock() {
DateUtil.setClock(Clock.systemDefaultZone());
}
这很简单。当您将预期的 LocalDate 初始化移动到 LocalDate.class 的模拟之后,那么 class 已经在全局范围内被模拟,就像在对 class 的每次调用中一样。这意味着它不会为您提供真正的 java 实现。这意味着您无法获得 LocalDate.of(2017, 10, 13) 的真正 java 实现,因为此时您用模拟版本覆盖了 class。
测试可以改进吗?是的,不要使用 powermock。
如果可以避免,使用 powermock 被认为是不好的做法。这是一个很长的故事,我不确定这是解释这一切的地方。它的简短版本:如果你不使用 power mock,你将不得不让你的代码更灵活。 Powermock 允许您作弊,而不是使您的代码灵活。当您使用 power mock 时,您在测试和生产代码中不会得到相同的行为。
阅读此处了解更多信息:
Why not PowerMock
日期在测试时总是很痛苦。但是使用 DateSupplier
可以很容易地修复它。
A DateSupplier
是一个 class 你可以在任何有 'now' 创建日期的地方注入。
用 DateSupplier.get()
替换日期创建。
测试时,您只需模拟 DateSupplier 和 return 您想要的日期。
可以在此处找到详细示例:https://dzone.com/articles/mocking-jodatimes-datetime-and。 (你真的不需要番石榴的供应商)
在这种情况下:在您的 DateUtil
class 中注入 DateSupplier
,并在测试期间将其替换为模拟!
考虑如下使用 PowerMockRunner
:
DateUtilTest
class
import com.reporting.utils.DateUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.time.LocalDate;
import java.util.Date;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
@PrepareForTest(DateUtil.class)
@RunWith(PowerMockRunner.class)
public class DateUtilTest {
@Test
public void getPreviousWorkingDayAsDate_whenMonday() {
//given
LocalDate date = LocalDate.of(2017, 10, 16);
LocalDate expected = LocalDate.of(2017, 10, 13);
mockStatic(LocalDate.class);
when(LocalDate.now()).thenReturn(date);
//when
Date previousWorkingDay = DateUtil.getPreviousWorkingDayAsDate();
//then
assertEquals(DateUtil.getDateFromLocalDate(expected), previousWorkingDay);
}
@Test
public void getPreviousWorkingDayAsDate2_whenMonday() {
//given
LocalDate date = LocalDate.of(2017, 10, 16);
mockStatic(LocalDate.class);
when(LocalDate.now()).thenReturn(date);
//when
Date previousWorkingDay = DateUtil.getPreviousWorkingDayAsDate();
LocalDate expected = LocalDate.of(2017, 10, 13);
//then
assertEquals(DateUtil.getDateFromLocalDate(expected), previousWorkingDay);
}
}
我想了解为什么 @Test
==> getPreviousWorkingDayAsDate2_whenMonday
将 expected
LocalDate
初始化移动到 LocalDate.class
的模拟之后失败?
此外,这个测试是否可以改进?
另外,这个测试可以改进吗?
是 - 重构 DateUtil 以能够使用特定 Clock
。例如:
public class DateUtil {
private static Clock clock = Clock.systemDefaultZone();
public static setClock(Clock clock) {
assertNotProduction(); // optionally check for an environment/system variable to throw exception if used in production
DateUtil.clock = clock;
}
public static Date getPreviousWorkingDayAsDate() {
LocalDate today = LocalDate.now(clock); // use clock
...
return ...;
}
}
然后单元测试不需要任何模拟。例如:
@Test
public void getPreviousWorkingDayAsDate_whenMonday() {
//given
LocalDate monday = LocalDate.of(2017, 10, 16);
Clock clock = Clock.fixed(monday.atStartOfDay(ZoneId.systemDefault()).toInstant(), ZoneId.systemDefault());
DateUtil.setClock(clock);
LocalDate lastFriday = LocalDate.of(2017, 10, 13);
//when
Date previousWorkingDay = DateUtil.getPreviousWorkingDayAsDate();
//then
assertEquals(DateUtil.getDateFromLocalDate(lastFriday), previousWorkingDay);
}
@After
public void resetClock() {
DateUtil.setClock(Clock.systemDefaultZone());
}
这很简单。当您将预期的 LocalDate 初始化移动到 LocalDate.class 的模拟之后,那么 class 已经在全局范围内被模拟,就像在对 class 的每次调用中一样。这意味着它不会为您提供真正的 java 实现。这意味着您无法获得 LocalDate.of(2017, 10, 13) 的真正 java 实现,因为此时您用模拟版本覆盖了 class。
测试可以改进吗?是的,不要使用 powermock。
如果可以避免,使用 powermock 被认为是不好的做法。这是一个很长的故事,我不确定这是解释这一切的地方。它的简短版本:如果你不使用 power mock,你将不得不让你的代码更灵活。 Powermock 允许您作弊,而不是使您的代码灵活。当您使用 power mock 时,您在测试和生产代码中不会得到相同的行为。
阅读此处了解更多信息: Why not PowerMock
日期在测试时总是很痛苦。但是使用 DateSupplier
可以很容易地修复它。
A DateSupplier
是一个 class 你可以在任何有 'now' 创建日期的地方注入。
用 DateSupplier.get()
替换日期创建。
测试时,您只需模拟 DateSupplier 和 return 您想要的日期。
可以在此处找到详细示例:https://dzone.com/articles/mocking-jodatimes-datetime-and。 (你真的不需要番石榴的供应商)
在这种情况下:在您的 DateUtil
class 中注入 DateSupplier
,并在测试期间将其替换为模拟!