在junit测试中模拟DateFormat类



我正在尝试模拟DateFormat类,因为它在我的单元测试范围内没有任何用途。我正在使用org.mockito.mockito库。

以下代码:

import static org.mockito.Mockito.when;
import static org.mockito.Mockito.any;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.junit.Before;
public class someTest {
@Mock
DateFormat formatter; 
@Before
public void before() {
MockitoAnnotations.initMocks(this);
when(formatter.format(any(Date.class))).thenReturn("2017-02-06");
}
}

给出以下错误:

org.mockito.exceptions.missing.InvalidUseOfMatchersException:参数匹配器的使用无效!预计有3名匹配者,记录了1名:

->在someTest.bfore(someTest.java:33)

如果匹配器与原始值组合,则可能会发生此异常://不正确:someMethod(anyObject(),"原始字符串");使用匹配器时,所有参数都必须由匹配器提供。例如://更正:someMethod(anyObject(),eq("匹配器字符串");

有关更多信息,请参阅javadoc For Matchers类。

位于java.text.DateFormat.format(未知来源)
someTest.bfore(someTest.java:33)

如何以正确的方式模拟DateFormat类?

问题在于format(Date date)的实现

public final String format(Date date) {
return format(date, new StringBuffer(),
DontCareFieldPosition.INSTANCE).toString();
}

正如你所看到的,这是决赛。Mockito无法模拟最终方法。相反,它将调用真正的方法。作为一种变通方法,您可以模拟方法format(date, new StringBuffer(), DontCareFieldPosition.INSTANCE)

when(formatter.format(any(Date.class), any(StringBuffer.class), 
any(FieldPosition.class)))
.thenReturn(new StringBuffer("2017-02-06"));

因此,当方法format(date)调用您的模拟方法时,结果将如您所期望的那样。

正如Serghey Bishyr所指出的,您正在尝试模拟final方法,这在Mockito中是无法完成的。

如果你的mocking框架不允许你做一些事情(比如mocking最后一个方法),你要么必须找到一个替代框架(比如Powermock),要么用另一种方式来解决它。

来自维基百科关于模仿的文章:

在单元测试中,模拟对象可以模拟复杂真实对象的行为,因此当真实对象不切实际或不可能合并到单元测试中时,模拟对象非常有用。如果一个对象具有以下任何特征,那么在其位置使用模拟对象可能会很有用:

  • 对象提供不确定的结果(例如当前时间或当前温度)
  • 它具有难以创建或再现的状态(例如网络错误)
  • 它很慢(例如,一个完整的数据库,必须在测试前初始化)
  • 它还不存在或可能改变行为
  • 它必须包括专门用于测试目的(而不是实际任务)的信息和方法

以上几点都不适用于您的代码,因此不需要使用mock。并且使用DateFormat的实际实现并非"不切实际或不可能"。

不提供模拟DateFormat,而是提供SimpleDateFormat:

formatter = new SimpleDateFormat("'2017-02-06'");

这将始终为任何输入返回2017-02-06,这显然是问题中的代码所希望的,因为'会导致它们之间的文本被逐字逐句地获取。

除了正确的答案之外,还有一个重要的注意事项:

when(formatter.format(any(Date.class))

如果这个方法不是最终的,你可以使用

when(formatter.format(any())

Mockito足够聪明,能够理解什么来了,什么出了(至少在使用Java8时)

您可以使用PowerMock来实现这一点。

在您的应用程序.gradle中添加此依赖项

testImplementation "org.powermock:powermock-module-junit4:${versions.powermock}"
testImplementation "org.powermock:powermock-module-junit4-rule:${versions.powermock}"
testImplementation "org.powermock:powermock-api-mockito2:${versions.powermock}"
testImplementation "org.powermock:powermock-classloading-xstream:${versions.powermock}"

然后

@RunWith(PowerMockRunner::class)
@PrepareForTest(android.text.format.DateFormat::class)
class YourTestClass {
@Before
fun setup() {
PowerMockito.mockStatic(android.text.format.DateFormat::class.java)
val format = SimpleDateFormat()
format.applyPattern("dd/MM/y") //your format here
PowerMockito.`when`(android.text.format.DateFormat.getDateFormat(any(Context::class.java))).thenAnswer {
format
}
}
... tests

相关内容

  • 没有找到相关文章

最新更新