1

我正在为一个需要在自身内部创建多个集合的类编写 JMock 测试。我正在为该类提供一个工厂,该工厂将在需要时生成一个 Collection。

interface Factory
{
    <T> Collection<T> newCollection();
}

class MyClass
{
    public MyClass(Factory f)
    {
        List<ThingA> la = f.newCollection();
        List<ThingB> lb = f.newCollection();
    }
}

现在可以了,但是当使用 JMock 测试“MyClass”时,我无法模拟此返回类型重载。

Collection<ThingA> ta = new LinkedList<ThingA>();
Collection<ThingB> tb = new LinkedList<ThingB>();
Collection<ThingC> tc = new LinkedList<ThingC>();

Factory mockFactory = context.mock(Factory.class);
context.checking(new Expectations()
{
    {
        allowing(mockFactory).newCollection(); will(returnValue(ta));
        allowing(mockFactory).newCollection(); will(returnValue(tb));
        allowing(mockFactory).newCollection(); will(returnValue(tc));
    }
}
);

// All return ta
Collection<ThingA> ta2 = mockFactory.newCollection();
Collection<ThingB> tb2 = mockFactory.newCollection();
Collection<ThingC> tc2 = mockFactory.newCollection();

有什么办法可以让它工作吗?我知道我可以传入一个 ThingX 作为参数,但如果它只是为了触发类型检查以进行测试,那似乎有点毫无意义。

我当前的修复将是添加一个序列,以便我强制执行对 newCollection 的调用顺序,但我可以看到这不起作用的情况(例如泛型类型的池)。

这可以做到吗?

4

1 回答 1

1

类型擦除妨碍了您尝试执行的操作。正如你提到的,我会简单地传递一个ThingX(或)。ThingX.class不幸的是,类型擦除会迫使你做那种骇人听闻的事情。

最好将您的代码分为两个域:通用感知和通用不感知,当您必须将事物从后者到前者粘合在一起时,没有办法避免做两者之一(对于控制一切):

要么传递参数以触发类型检查(如您所建议):

Collection<ThingA> ta2 = mockFactory.newCollection(ThingA.class);
Collection<ThingB> tb2 = mockFactory.newCollection(ThingB.class);
Collection<ThingC> tc2 = mockFactory.newCollection(ThingC.class);

或将不知道泛型的代码封装到以下方法中:a) 泛型感知;b) 具有@SuppressWarnings("unchecked")注释以抑制从一个域分配到另一个域时会收到的警告。

class MockFactoryThingie
{
   /**
    *@SuppressWarnings("unchecked")
    */
   Collection<ThingA> newThingACollection()
   { 
     return (Collection<ThingA>) ... your generic-unaware collection thing...   
   }
}

无论哪种方式都很笨拙。我们要感谢我们的 Java/JCP 霸主赐予我们这种类型擦除的宝石 :)

于 2011-08-22T15:06:00.400 回答