我正在进行一些服务测试,我正在测试一个从使用泛型的类扩展的具体类 .
服务层的示例设置如下:
public abstract class AbstractService <E extends AbstractEntity, IT extends AbstractItem> {
public void deleteAllItems(E entity) {
List<IT> items = new ArrayList<IT>(entity.getItems());
for(IT item : items) {
//Yada, yada
}
}
}
public class Service extends AbstractService<Entity, Item> {
}
public class OtherService() {
@Inject
private ServiceManager serviceManager;
public void deleteItems(Entity e) {
serviceManager.getService().deleteAllItems(e);
}
}
然后测试它我有以下内容:
public class Test {
private Service service;
private OtherService otherService;
private ServiceManager serviceManager;
@BeforeMethod
public void setup() {
serviceManager= mock(serviceManager.class);
service= mock(Service.class);
when(serviceManager.getService()).thenReturn(service);
otherService=injector.getInstance(OtherService.class);
}
@Test
public void test() {
Entity e = new Entity();
//Attach some items
otherService.deleteItems(e);
verify(service).deleteAllItems(e);
}
}
这应该调用 OtherService
,它存在(我们使用注入来获取对象),然后调用方法 deleteItems()
,而后者应该在 Service
上调用 deleteAllItems()
. 在我实现Java泛型之前,这很好用,但是由于我已经实现了Java泛型,因此Mockito测试失败并出现以下异常:
java.lang.NoSuchMethodError:Service.deleteAllItems(Entity;)V at Test.test(Test.java:XXX)org.mockito.exceptions.misusing.UnfinishedVerificationException:缺少方法调用验证(mock): - > at Test .test(Test.java:XXX)正确验证的示例:verify(mock).doSomething()此外,此错误可能会显示,因为您验证了:final / private / equals()/ hashCode()方法 . 这些方法无法进行存根/验证 .
听起来似乎无法找到方法 . 我是应该嘲笑 AbstractService
的抽象类还是还有其他我缺少的东西?
EDIT
从我所看到的Mockito内部工作方式来看,它创建了一个这样的实例:
public void AbstractService.deleteAllItems(Entity)
对于 MockitoMethod
对象,这样才有意义 Service.deleteAllItems()
"isn't called",看来Mockito假设只调用了基类 . 所以看来我需要模拟基类 . 我对这些建议持开放态度
3 回答
我可以建议将问题本地化 - 要么是在嘲笑:
或者在注入中(删除继承和泛型):
迭代地分解问题,你会发现原因 .
当您创建泛型类的非泛型子类时,Java会为使用泛型类型的任何方法创建“桥接方法” . 桥接方法看起来像继承的方法,但使用为泛型参数而不是泛型指定的特定类 .
Java创建这些方法是因为子类的方法不是通用的,因此它们需要"look like"非泛型方法(即不受擦除,反射将按预期工作,等等) . 有关详细信息,请参见this answer .
解决方案是让Mockito模拟
serviceManager.getService()
返回的类型 .经过进一步的调查,我找到了一种方法来迫使Mockito打电话给正确的 class . 正如我简要提到的那样,我们正在使用注射来获得物体 . 在设置过程中,我们确实完成了注射器的设置,我没有感觉到导致问题 . 但它确实提出了一个解决方案 . 这就是我们称之为:
为了解决这个问题,我们只是将
AbstractService
类绑定到Service
类的模拟实例,如下所示:所以现在,当Mockito尝试获取
AbstractService
的实例时,它会调用模拟的Service
并解决我们的问题 .如果有人有任何反馈它有一个替代解决方案,然后随意发布,我可以测试它,并检查是否有更好的方法,我们正在做什么 .