我正在尝试模拟一个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.misusing.InvalidUseOfMatchersException: 参数匹配器的使用无效! 3匹配预期,1记录:
- >在someTest.before(someTest.java:33)
如果匹配器与原始值组合,则可能会发生此异常: //不正确: someMethod(anyObject(),“raw String”);使用匹配器时,所有参数都必须由匹配器提供。例如: //正确: someMethod(anyObject(),eq(“by matcher”));
有关更多信息,请参阅Matchers类的javadoc。
at java.text.DateFormat.format(Unknown Source)
在 someTest.before(someTest.java:33)
如何以正确的方式模拟DateFormat类?
答案 0 :(得分:3)
问题在于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)
将调用您的模拟方法时,结果将如您所愿。
答案 1 :(得分:3)
正如Serghey Bishyr指出的那样,你试图嘲笑final
method,这在Mockito无法做到。
如果你的模拟框架不允许你做某事(比如模拟最终方法),你要么必须找到一个替代框架(比如Powermock),要么以另一种方式解决它。
来自Wikipedia article about mocks:
在单元测试中,模拟对象可以模拟复杂的真实对象的行为,因此当真实对象不可行或不可能合并到单元测试中时非常有用。如果对象具有以下任何特征,则在其位置使用模拟对象可能很有用:
- 对象提供非确定性结果(例如当前时间或当前温度);
- 它具有难以创建或复制的状态(例如网络错误);
- 它很慢(例如一个完整的数据库,必须在测试之前进行初始化);
- 它尚不存在或可能改变行为;
- 它必须包含专门用于测试目的的信息和方法(而不是其实际任务)。
以上几点均不适用于您的代码,因此无需使用模拟。使用DateFormat
的实际实现并不“不切实际或不可能”。
不提供模拟的DateFormat
,而是提供SimpleDateFormat
:
formatter = new SimpleDateFormat("'2017-02-06'");
对于任何输入,这将始终返回2017-02-06
,这显然是问题代码所需要的,因为'
会导致它们之间的文字被字面意思理解。
答案 2 :(得分:0)
除了正确答案之外,还有一个重要的注意事项:
when(formatter.format(any(Date.class))
如果方法不是最终的,你可以选择
when(formatter.format(any())
Mockito足够聪明,能够理解发生了什么以及发生了什么(至少在使用Java8时)
答案 3 :(得分:0)
您可以使用PowerMock来做到这一点。
在您的app.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