使用所述类的抽象版本模拟泛型类

时间:2016-06-28 11:22:55

标签: java unit-testing generics mockito

我试图嘲笑一个抽象类,但从我所看到的,我不认为这是可能的。我们有一些使用泛型的类,它必须扩展特定的抽象类。他们中有一大群人,他们被成功嘲笑了。抽象类有一个处理返回泛型的方法,如下所示:

public abstract class ChildPresenter <T extends ChildView> {
    private T view;

    public abstract T getView();
}

我们正在测试的课程中包含以下内容:

public class ParentPresenter {
    private ConcreteChildPresenter1 childPresenter1;
    private ConcreteChildPresenter2 childPresenter2;
    private ConcreteChildPresenter3 childPresenter3;
    private ConcreteChildPresenter4 childPresenter4;
    List<ChildPresenter> childPresenters;
}

在构造函数中,这些类使用Google Guice注入,设置为变量,并添加到子呈现器列表中。

测试中的方法是迭代所有childPresenters个对象并运行方法getView()的方法。

我在测试课中尝试过这种方式:

public class ParentPresenterTest {
    private ConcreteChildPresenter1 childPresenter1;
    private ConcreteChildPresenter2 childPresenter2;
    private ConcreteChildPresenter3 childPresenter3;
    private ConcreteChildPresenter4 childPresenter4;
    private List<ChildPresenter> childPresenters;

    //This is an abstract class 
    private ChildView childView;

    @BeforeTest
    public void createInjector() {
        Guice.createInjector(...//Creates a fake module and does binding for the variables mentioned earlier
            //e.g.
            childPresenter1 = mock(ConcreteChildPresenter1.class);
            binder.bind(ConcreteChildPresenter1.class).toInstance(childPresenter1);
            //e.t.c for other variables

            //Same for child view
            childView = mock(ChildView.class);
            binder.bind(ChildView.class).toInstance(childView);
        }

        childPresenters = new ArrayList<ChildPresenter>();
        childPresenters.add(childPresenter1);
        //Add all child presenters

        for(ChildPresenter childPresenter : childPresenters) {
            when(childPresenter.getView()).thenReturn(childView);
        }
    }
}

问题发生在第when(childPresenter.getView()).thenReturn(childView);行,因为Mockito抱怨​​以下消息:

  

org.mockito.exceptions.misusing.WrongTypeOfReturnValue:

     

ChildView $$ EnhancerByMockitoWithCGLIB $$ 2f6a4bd5

     getView()不能返回

getView()应该返回ConcreteChildView1

     

***如果您不确定为什么上述错误,请继续阅读。由于上述语法的性质,可能会出现问题,原因是:

     
      
  1. 此异常可能在错误编写的多线程测试中发生。有关并发性测试的限制,请参阅Mockito常见问题解答。

  2.   
  3. 使用when(spy.foo())。then()语法时,间谍是存根的。使用doReturn | Throw()方法系列来存储间谍更安全。更多关于Mockito.spy()方法的javadocs。

  4.   

我可以理解,但是当我想要做的就是使用以下内容确认被称为单个方法的模拟ChildView时,模拟每个具体的ChildView似乎是浪费:

verify(childView, atLeast(childPresenters.size())).getView();

还有其他办法吗?我可以以某种方式使用模拟的抽象类来代替具体的抽象类吗?

编辑以下是getView()方法实施方式的具体版本:

public ConcreteChildPresenter1<ConreteChildView1> {

    @Override
    public ConreteChildView1 getView() {
        view.buildView();
        return view;
    }
}

所有子视图扩展的抽象ChildView类:

public abstract ChildView {

    public abstract void buildView();
}

2 个答案:

答案 0 :(得分:2)

由于每个子演示者都返回一个特定类型的视图,因此您不能像您已经理解的那样用抽象类ChildView的模拟替换它们。

只有在提供如下所述的正确实现时,才能在运行时获取具体类型的ChildView:Get generic type of class at runtime

然后你可以用这种方式初始化演示者的模拟:

for(ChildPresenter childPresenter : childPresenters) {
    //this getter returns the needed runtime class
    when(childPresenter.getView()).thenReturn(mock(childPresenter.getViewType())); 
}

答案 1 :(得分:1)

根据改进,模拟的ChildView基于错误的超类。我想你可以在Guice注射器上修复它:

Guice.createInjector(...//Creates a fake module and does binding for the variables mentioned earlier
    // ...
    //Same for child view
    childView = mock(ConcreteChildPresenter1.class); // this is the fix
    binder.bind(ChildView.class).toInstance(childView);
}