JMock 通用返回类型

发布于 2024-11-30 12:50:45 字数 1271 浏览 1 评论 0原文

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

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 的调用顺序,但我可以看到这不起作用的情况(例如通用类型的池化)。

这可以做到吗?

I'm writing a JMock test for a class that needs to create a number of collections within itself. I am supplying the class with a factory which will generate a Collection when needed.

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

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

Now that works but when using JMock to test "MyClass", I cannot mock this return type overloading.

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();

Is there any way to get this to work? I know I could pass in a ThingX in as an argument but that seems a bit pointless if it's just to trigger type checking for testing.

My current fix is going to be to add a sequence so that I'm enforcing the order of the calls to newCollection but I can see situations where this would not work (say pooling of generic types).

Can this be done?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

反话 2024-12-07 12:50:45

类型擦除妨碍了您想要做的事情。正如您提到的,我只是传递一个 ThingX (或 ThingX.class)。不幸的是,类型擦除迫使你做那种hacky的事情。

最好将您的代码视为分为两个域:通用感知和通用不感知,并且当您必须将事物从后一个域粘合到前一个域时,没有办法避免执行这两个域之一(对于保持事情在控制之下):

要么传递参数只是为了触发类型检查(如您所建议的):

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 霸主赐予我们这个类型擦除的宝石:)

Type erasure is getting in the way to what you are trying to do. I'd simply pass a ThingX (or ThingX.class) as you mentioned. Unfortunately, type erasure forces you to do that type of hacky things.

It's best to think of your code as divided into two domains: generic-aware and generic-unaware, and when you have to glue things together from one the later to the former, there is no way to avoid doing one of the two (for keeping things under control):

either pass parameters just to trigger type checking (as you suggested):

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

or encapsulate generics-unaware code into methods that are a) generics-aware, and b) have a @SuppressWarnings("unchecked") annotation to suppress the warning you'll get when assigning from one domain to the other.

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

Either way is clunky. We gotta thank our Java/JCP overlords for bestowing unto us this gem that is type erasure :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文