Java 是否可以创建一个使用 EasyMock 实现多个接口的模拟对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1170708/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:30:23  来源:igfitidea点击:

Is it possible to create a mock object that implements multiple interfaces with EasyMock?

javaunit-testingmockingrhino-mockseasymock

提问by Daniel Fortunov

Is it possible to create a mock object that implements several interfaces with EasyMock?

是否可以创建一个使用 EasyMock 实现多个接口的模拟对象?

For example, interface Fooand interface Closeable?

例如,接口Foo和接口Closeable

In Rhino Mocks you can provide multiple interfaces when creating a mock object, but EasyMock's createMock()method only takes one type.

在 Rhino Mocks 中你可以在创建一个 mock 对象时提供多个接口,但是 EasyMock 的createMock()方法只接受一种类型。

Is it possbile to achieve this with EasyMock, without resorting to the fallback of creating a temporary interface that extends both Fooand Closeable, and then mocking that?

是否可以使用 EasyMock 来实现这一点,而不诉诸于创建一个扩展了Foo和的临时接口,Closeable然后模拟它?

采纳答案by Nick Holt

EasyMock doesn't support this so you're stuck with fallback of the temporary interface.

EasyMock 不支持此功能,因此您会遇到临时接口的回退问题。

As an aside, I smell a little bit of a code wiff - should a method really be treating an object as 2 different things, the Fooand Closeableinterface in this case?

顺便说一句,我闻到了代码WIFF一点点-应的方法真的治疗对象为2分不同的东西,在FooCloseable在这种情况下接口?

This implies to me that the method is performing multiple operations and while I suspect one of those operations is to 'close' the Closeable, wouldn't it make more sense for the calling code to decide whether or not the 'close' is required?

这对我来说意味着该方法正在执行多个操作,虽然我怀疑其中一个操作是“关闭” Closeable,但调用代码决定是否需要“关闭”不是更有意义吗?

Structuring the code this way keeps the 'open' and 'close' in the same try ... finallyblock and IMHO makes the code more readable not to mention the method more general and allows you to pass objects that only implement Foo.

以这种方式构建代码可以将“打开”和“关闭”保持在同try ... finally一块中,恕我直言,使代码更具可读性,更不用说更通用的方法,并允许您传递仅实现Foo.

回答by extraneon

have you considered something like:

你有没有考虑过这样的事情:

interface Bar extends Foo, Closeable {
}

and then mock interface Bar?

然后模拟界面吧?

回答by Rogério

To the best of my knowledge, the only mocking tool for Java that has explicit support for mocking multiple interfaces is JMockit. (My inspiration for adding this feature came from Moq and Rhino Mocks, which are .NET tools.)

据我所知,唯一明确支持模拟多个接口的 Java 模拟工具是JMockit。(我添加此功能的灵感来自 Moq 和 Rhino Mocks,它们是 .NET 工具。)

An example (from the mockit.ExpectationsUsingMockedTestJUnit 4 test class):

一个例子(来自mockit.ExpectationsUsingMockedTestJUnit 4 测试类):


@Test
public <M extends Dependency & Runnable> void mockParameterWithTwoInterfaces(final M mock)
{
   new Expectations()
   {
      {
         mock.doSomething(true); returns("");
         mock.run();
      }
   };

   assertEquals("", mock.doSomething(true));
   mock.run();
}

Dependencyand Runnableare interfaces. The doSomethingmethod belongs to the first, and runto the second.

Dependency并且Runnable是接口。该doSomething方法属于第一种,也属于run第二种。

回答by Thomas Dufour

Although I fundamentally agree with Nick Holt's answer, I thought I should point out that mockitoallows to do what you ask with the following call :

尽管我从根本上同意 Nick Holt 的回答,但我想我应该指出,mockito允许通过以下调用执行您的要求:

Foo mock = Mockito.mock(Foo.class, withSettings().extraInterfaces(Bar.class));

Obviously you'll have to use the cast: (Bar)mockwhen you need to use the mock as a Barbut that cast will not throw ClassCastException

显然,您必须使用演员表:(Bar)mock当您需要将模拟用作 aBar但该演员表不会抛出ClassCastException

Here is an example that is a bit more complete, albeit totally absurd:

这是一个更完整的例子,尽管完全荒谬:

import static org.junit.Assert.fail;
import org.junit.Test;
import static org.mockito.Mockito.*;
import org.mockito.Mockito;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import org.hamcrest.Matchers;

import java.util.Iterator;


public class NonsensicalTest {


    @Test
    public void testRunnableIterator() {
        // This test passes.

        final Runnable runnable = 
                    mock(Runnable.class, withSettings().extraInterfaces(Iterator.class));
        final Iterator iterator = (Iterator) runnable;
        when(iterator.next()).thenReturn("a", 2);
        doThrow(new IllegalStateException()).when(runnable).run();

        assertThat(iterator.next(), is(Matchers.<Object>equalTo("a")));

        try {
            runnable.run();
            fail();
        }
        catch (IllegalStateException e) {
        }
    }

回答by Haroldo_OK

Another way to solve this problem is to use a CGLib mixin:

解决此问题的另一种方法是使用CGLib mixin

final Interface1 interface1 = mockery.mock(Interface1.class);
final Interface2 interface2 = mockery.mock(Interface2.class);

service.setDependence(Mixin.create(new Object[]{ interface1, interface2 }));

mockery.checking(new Expectations(){{
    oneOf(interface1).doSomething();
    oneOf(interface2).doNothing();
}});

service.execute();

Whether or not this is a good idea, it's something up to discussion...

这是否是一个好主意,这有待讨论……

回答by Nicolas Filotto

An alternative of the most voted answerstill based on Mockitobut with annotations. You can set the extraInterfacesdirectly from the Mockannotation as next:

投票最多的答案的替代方案仍然基于Mockito,但带有注释。您可以extraInterfaces直接从Mock注释中设置 ,如下所示:

@RunWith(MockitoJUnitRunner.class)
public class MyTest {
    @Mock(extraInterfaces = Closeable.class)
    private Foo foo;
    ...
}

NB:extraInterfacesis of type Class<?>[]so you can specify several interfaces if needed.

注意:extraInterfaces是类型,Class<?>[]因此您可以根据需要指定多个接口。

If you need to mock method calls of the extra interfaces you will need to cast your mock. For example let's say that I want to throw an IOExceptionwhen I call close()on my mock foo, the corresponding code would then be:

如果您需要模拟额外接口的方法调用,您将需要转换您的模拟。例如,假设我想IOException在调用close()我的 mock时抛出 an foo,则相应的代码将是:

Mockito.doThrow(IOException.class).when((Closeable) foo).close();