Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java泛型-方法不适用于Mockito生成的存根_Java_Generics_Mockito - Fatal编程技术网

Java泛型-方法不适用于Mockito生成的存根

Java泛型-方法不适用于Mockito生成的存根,java,generics,mockito,Java,Generics,Mockito,我有一个ThingsProvider接口,我正试图用Mockito(简化版)进行测试,定义如下: interface ThingsProvider { Iterable<? extends Thing> getThings() } 。。。但这在非测试代码中显然是不好的 我的问题: 为什么这是一个错误?很明显,我返回的对象扩展了东西,这正是接口所期望的 有没有更好的办法解决这个问题?也许我的界面定义不同?到目前为止,除了测试之外,我还没有遇到这个问题 关于#2-我之所以不简单

我有一个
ThingsProvider
接口,我正试图用Mockito(简化版)进行测试,定义如下:

interface ThingsProvider {
    Iterable<? extends Thing> getThings()
}
。。。但这在非测试代码中显然是不好的

我的问题:

  • 为什么这是一个错误?很明显,我返回的对象扩展了
    东西
    ,这正是接口所期望的
  • 有没有更好的办法解决这个问题?也许我的界面定义不同?到目前为止,除了测试之外,我还没有遇到这个问题
  • 关于#2-我之所以不简单地返回Iterable,主要原因是有几个不同的扩展,其中具体类型中包含返回特定子类型的东西,最后我遇到了类似类型不匹配的问题:无法从Iterable转换为Iterable——也许解决方案是解决此问题的更好方法


    对于那些不太熟悉Mockito的人,下面是#1的更纯Java版本:

    public static void main(String...args) {
        List<Integer> ints = Arrays.asList(1,2,3);
        blah(ints);
    
        Foo<Number> foo1 = new Foo<Number>();
        foo1.bar(ints);  // This works
    
        Foo<? extends Number> foo2 = new Foo<Number>();
        foo2.bar(ints);  // NO COMPILEY!
    } 
    
    private static void blah(List<? extends Number> numberList) {
        // something
    }
    
    public static class Foo<T> {
        public Object bar(List<? extends T> tList) {
            return null;
        }
    }
    
    publicstaticvoidmain(字符串…参数){
    List ints=Arrays.asList(1,2,3);
    废话;
    Foo foo1=新的Foo();
    foo1.bar(ints);//这很有效
    
    Foo重构为两个步骤

    OngoingStubbing<Iterable<? extends Thing>> stub =  when(thingsProvider.getThings());
    stub.thenReturn(things);
    

    正如您所观察到的,返回类型中的通配符对于子类实现非常方便

    不过,它对方法的调用者没有太大影响;如果愿意,您可以将其更改为
    Iterable
    ;在javadoc上更简单,代价是子类实现者。子类可以在必要时执行强制转换,例如
    List=>Iterable
    ,这要归功于擦除


    出现问题的原因是通配符捕获;基本上,在计算上下文表达式之前,每个表达式都首先进行通配符捕获

        foo( arg )
    

    arg
    总是先捕获通配符,然后再执行方法适用性/重载/推断。在您的情况下,您可以尝试更通用的类型
    Iterablecan
    Mockito.Hm,这是一种有趣的替代解决方法!由于类型安全问题,不一定比问题中概述的当前解决方法更好…@Chri你的意思是在编辑之前吗?是的,键入安全性不太好。我不喜欢这样删除答案的解决方案。是的,我在上面的评论中引用了原始答案。我将在稍后仔细查看修订版。谢谢更新!
    
    OngoingStubbing<Iterable<? extends Thing>> stub =  when(thingsProvider.getThings());
    stub.thenReturn(things);
    
    Mockito.<Iterable<? extends Thing>>when(thingsProvider.getThings())
    
        foo( arg )
    
    Mockito.<Iterable<? extends Thing>>when(...
    
    OngoingStubbing<Iterable<? extends Thing>> stub =  when(...
    
    static <T> OngoingStubbing<T> whenX( Supplier<T> sup )
    {    
        return Mockito.when( sup.get() );
    }
    
    whenX(thingsProvider::getThings).thenReturn(things);
    // T = Iterable<? extends Thing>
    
    List<Thing> things = ...;
    
    ThingsProvider thingsProvider = ()->things;