java更改单元测试的私有方法行为
这不是我的代码的样子,但它将接近我想要的示例
class Phone {
public makeCall(String number) {
addEntryToCallLog(number)
//eventually make a call
}
private void addEntryToCallLog(String number) {
//make database calls
}
}
class PhoneTest {
Phone phone
@Test
public void canMakeACall() {
//mock the behaviour of phone.addEntryToCallLog to prevent database exceptions
phone.makeCall("1223");
//Assert somehow that call was made << --IGNORE this NOT IMPORTANT
}
}
我想在单元测试中测试“makeCall”,但当我这样做时,代码会抛出一些数据库异常,从而破坏我的测试。 我认为能够测试模仿java私有方法的行为是合理的,因为这允许所有测试的行为一致
我过去使用过groovy,通过它,我可以使用spock来模拟私有方法的行为。我也可以使用元类为我创建的实例做同样的事情。但在java中,似乎没有一种直接的方法可以做到这一点
我也尝试过mockito和power mockito,但它们允许我更改私有方法的返回值,但不允许我更改行为
这似乎是一件很明显的事情,有人已经处理过了。我想我错过了什么。但这是什么呢
# 1 楼答案
我的建议是将可视性从} annotation 或} 来“部分模拟”您的内部方法,正如DTing在另一个答案中提到的那样,以替换实际实现的行为
private
放宽到包私有,可能带有^{/** Visible for testing. */
注释。在这一点上,您可以使用^{这里的主要问题是Mockito最擅长将接口转换为存根实现。然而,私有方法非常有意地不是接口的一部分,因此Java通过一些普通Mockito依赖的反射特性使它们成为harder to access。(在幕后,Mockito正在创建您要模拟的类的子类,子类通常不能覆盖私有方法。)
您还应该记住,单元测试最好是将类作为一个单元进行测试,而不必深入研究实现细节。如果说您试图替换私有方法的行为,则表明您的类需要一个尚不存在的seam。您可以考虑重构依赖注入:
。。。这样,您就可以选择任何想要的调用记录器,包括在生产中访问数据库、在测试中伪造或模拟它,或者在将来用批处理版本替换它。同样地,对于将
addEntryToCallLog
包私有化或protected
:您指出子类可以改变它们向调用日志添加条目的方式,这正是您在测试中试图做的,并且承认这将帮助Java VM和代码的读者理解行为在什么时候可以改变综上所述,如果您只想使用PowerMockito替换实现,那么可以使用PowerMockito的^{} 和^{} 为您的私有方法提供不同的行为。只需记住,您有机会改进设计,并花更少的时间和精力解决实现细节