我的代码中有类似这样的内容:
private void doSomething() {
Calendar today = Calendar.getInstance();
....
}
如何在我的JUnit测试中“模拟”它以返回特定日期?
您可以使用PowerMock与Mockito结合来模拟它:
在您的类顶部:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassThatCallsTheCalendar.class})
成功的关键在于,在使用Calendar类时,需要将它放到PrepareForTest中而不是直接使用Calendar本身,因为它是一个系统类。(我个人在找到这个方法之前搜索了很多次)mockStatic(Calendar.class);
when(Calendar.getInstance()).thenReturn(calendar);
PowerMockito.whenNew(Calendar.getInstance()).withAnyArguments().thenReturn(MY_INSTANCE_OBJECT_TO_FEED);
。 - Payam将Calendar
实例注入到你设置那天的任何方法/类中。
private void method(final Calendar cal)
{
Date today = cal.getTime();
}
使用JodaTime代替Calendar
。这不仅是一个选项,更像是一种建议,因为JodaTime会让你的生活变得更轻松。你仍然需要将这个时间注入到该方法中。
DateTime dt = new DateTime();
Date jdkDate = dt.toDate();
在某个接口内包装Calendar
,以允许您获取时间。然后你只需要模拟这个接口并让它返回一个常量的Date
。
Date today = calendarInterfaceInstance.getCurrentDate()
DateTimeUtils
类有一些静态方法,可以为所有其他 Joda Time 对象设置当前时间。这对于将时间设置为某个时刻(例如用于测试)非常有用。 - Jesper不要模拟它 - 而是引入一个可以模拟日期的方法。像这样:
interface Utility {
Date getDate();
}
Utilities implements Utility {
public Date getDate() {
return Calendar.getInstance().getTime();
}
}
然后你可以将这个内容注入到你的类中,或者使用一个带有一堆静态方法和接口load方法的helper类:
public class AppUtil {
private static Utility util = new Utilities();
public static void load(Utility newUtil) {
this.util = newUtil;
}
public static Date getDate() {
return util.getDate();
}
}
然后在你的应用程序代码中:
private void doSomething() {
Date today = AppUtil.getDate();
....
}
你可以在测试方法中加载一个模拟接口。@Test
public void shouldDoSomethingUseful() {
Utility mockUtility = // .. create mock here
AppUtil.load(mockUtility);
// .. set up your expectations
// exercise the functionality
classUnderTest.doSomethingViaAPI();
// ... maybe assert something
}
另请参阅应该只模拟您拥有的类型吗? 和 测试异味-一切都被模拟
Calendar endOfMarch = Calendar.getInstance();
endOfMarch.set(2011, Calendar.MARCH, 27);
PowerMockito.mockStatic(Calendar.class);
Mockito.when(Calendar.getInstance()).thenReturn(endOfMarch);
编写一个名为 DateHelper
的类,其中包含一个方法 getCalendar
,该方法返回 Calendar.getInstance()
。对正在测试的类进行重构,使其具有类型为 DateHelper
的成员变量,并具有注入该成员变量的构造函数。在测试中使用该构造函数,以注入 DateHelper
的模拟版本,其中 getCalendar
已被存根以返回某些已知日期。
private lateinit var calendar: Calendar
@Before
fun setup() {
calendar = mockk(relaxed = true)
mockkStatic(Calendar::class)
every { Calendar.getInstance() } returns calendar
}
@Test
fun `test date when date is less than 16 month is 0`() {
every { calendar[Calendar.DAY_OF_MONTH] } returns 12
every { calendar[Calendar.MONTH] } returns 0
every { calendar[Calendar.YEAR] } returns 2023
// assert here
}
Calendar
类。它是为了弥补Date
的不足而进行的一次大部分失败的尝试,并且一直很难使用。随着近10年前发布的现代Java日期和时间API - java.time的发布,Date
和Calendar
都已经过时了。java.time具有许多功能,其中包括提供一个由你控制的时钟给获取当前时间的方法,因此你根本不需要进行模拟。 - undefinedCalendar
类。它是对Date
的不足之处进行弥补的大部分失败尝试,而且一直很麻烦。随着近10年前发布的Java 日期和时间 API,java.time的发布,Date
和Calendar
都已过时。Java.time具有许多功能,其中包括向获得当前时间的方法提供您控制的时钟的可能性,因此您根本不需要模拟。 - Ole V.V.dates
和老旧的 Calendar 的 thymeleaf 模板 :'( - Sylvaindates
的thymeleaf模板,所以还得用老旧的Calendar :'( - undefinedCalendar.getInstance()
,而是使用 Mockito
方法返回所需的内容。
例如:@Test
fun italianLocale_returnsItalianFormatDate() {
val calendar: Calendar = Mockito.mock(Calendar::class.java)
Mockito.`when`(calendar.get(Calendar.DAY_OF_MONTH)).thenReturn(27)
Mockito.`when`(calendar.get(Calendar.YEAR)).thenReturn(2023)
Mockito.`when`(calendar.get(Calendar.MONTH)).thenReturn(1)
val formatted = calendar.toReadableDate()
assert(formatted == "27/01/2023")
}
使用以下代码:
testImplementation ("org.mockito.kotlin:mockito-kotlin:x.x.x")
testImplementation "org.mockito.kotlin:mockito-kotlin:x.x.x"
@Test
public void doSomething() {
listCalendarParams("now", Calendar.getInstance());
Calendar fakedCalendar = new GregorianCalendar(2023, Calendar.OCTOBER, 15, 10, 15);
listCalendarParams("mock", fakedCalendar);
try (MockedStatic<Calendar> mockedStatic = Mockito.mockStatic(Calendar.class, Mockito.CALLS_REAL_METHODS)) {
mockedStatic.when(Calendar::getInstance).thenReturn(fakedCalendar);
//This or any method here using Calendar.getInstance() will be replaced by mock defined above
Calendar calendar = Calendar.getInstance();
listCalendarParams("evaluated", calendar);
assertEquals(Calendar.OCTOBER, calendar.get(Calendar.MONTH));
assertEquals(15, calendar.get(Calendar.DAY_OF_MONTH));
assertEquals(10, calendar.get(Calendar.HOUR_OF_DAY));
assertEquals(15, calendar.get(Calendar.MINUTE));
}
}
private static void listCalendarParams(String nameOfCal, Calendar calendar) {
System.out.println(nameOfCal + ":\t" +
new SimpleDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss")
.format(calendar.getTime()));
}3
输出:
now: 2023-11-27T14:00:48 //This will change anytime you run it.
mock: 2023-10-15T10:15:00
evaluated: 2023-10-15T10:15:00
today
是一个类成员(字段)还是方法内的局部变量? - Andreas Dolkjava.time.Clock
类上的static
方法来伪造一个时钟。将伪造的Clock
实例传递给各种java.time.*
类上的不同方法。 - undefined