我正在进行一些服务测试,我正在测试一个从使用泛型的类扩展的具体类。
服务层的示例设置如下:
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()
,然后调用{{1}在deleteAllItems()
上。在我实现Java泛型之前,这很好用,但是由于我已经实现了Java泛型,因此Mockito测试失败并出现以下异常:
java.lang.NoSuchMethodError: Service.deleteAllItems(实体;)V 在 Test.test(Test.java:XXX) org.mockito.exceptions.misusing.UnfinishedVerificationException: 缺少方法调用验证(模拟): - &GT;在Test.test(Test.java:XXX)
正确验证的示例: 验证(模拟).doSomething()
此外,此错误可能会显示,因为您验证以下任一项: final / private / equals()/ hashCode()方法。那些方法不能 存根/验证。
听起来它无法找到方法。我应该嘲笑Service
的抽象类还是还有其他我缺少的东西?
修改
从我在Mockito内部工作中所看到的情况来看,它创造了一个这样的例子:
AbstractService
对于public void AbstractService.deleteAllItems(Entity)
对象,因此MockitoMethod
&#34;不被称为&#34;是有道理的,看来Mockito假定只调用了基类。所以看来我需要模拟基类。我将进一步调查,但如果有人有任何其他想法,我愿意接受建议
答案 0 :(得分:1)
我可以建议将问题本地化 - 要么就是在嘲笑:
@Test
public void test() {
Entity e = new Entity();
service.deleteItems(e); // Note! 'service' itself, not an 'otherService'
verify(service).deleteAllItems(e);
}
或注入(删除继承和泛型):
public class Service /*extends AbstractService<Entity, Item>*/ {
public void deleteAllItems(Entity entity) {
//...
}
}
迭代地解决问题,你会找到原因。
答案 1 :(得分:0)
当您创建泛型类的非泛型子类时,Java会为使用泛型类型的任何方法创建“桥接方法”。桥接方法看起来像是继承的方法,但使用为泛型参数而不是泛型指定的特定类。
Java创建这些方法是因为子类的方法不是通用的,因此它们需要“看起来像”非泛型方法(即不受擦除,反射将按预期工作,等等)。有关详细信息,请参阅this answer。
解决方案是让Mockito模拟serviceManager.getService()
返回的类型。
答案 2 :(得分:0)
经过进一步调查,我找到了一种方法迫使Mockito打电话给正确的班级。正如我简要提到的那样,我们正在使用注射来获取物体。在设置过程中,我们确实完成了喷射器的设置,我没有感觉到导致了这个问题。但它确实提出了一个解决方案。这就是我们称之为:
Injector injector = Guice.createInjector(new Module() {
@Override
public void configure(Binder binder) {
service = mock(Service.class);
binder.bind(Service.class).
toInstance(service);
}
要解决这个问题,我们只是将AbstractService
类绑定到Service
类的模拟实例,如下所示:
Injector injector = Guice.createInjector(new Module() {
@Override
public void configure(Binder binder) {
service = mock(Service.class);
binder.bind(Service.class).
toInstance(service);
binder.bind(AbstractService.class).
toInstance(service);
}
现在,当Mockito尝试获取AbstractService
的实例时,它会调用模拟的Service
并解决我们的问题。
如果有人有任何反馈,那么有一个替代解决方案,然后随时发布,我可以测试它,并检查是否有更好的方法,我们正在做什么。