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

时间:2009-07-23 09:50:41

标签: java unit-testing mocking rhino-mocks easymock

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

例如,界面Foo和界面Closeable

在Rhino Mocks中,您可以在创建模拟对象时提供多个接口,但EasyMock的createMock()方法只需要一种类型。

是否有可能使用EasyMock实现这一点,而不是依靠创建一个扩展FooCloseable的临时接口的后备,然后嘲笑它?

6 个答案:

答案 0 :(得分:66)

虽然我从根本上同意尼克霍尔特的回答,但我想我应该指出mockito允许通过以下电话做你所要求的事情:

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

显然,当您需要将模拟用作(Bar)mock时,您将不得不使用强制转换:Bar但该强制转换不会抛出ClassCastException

这是一个更完整的例子,虽然完全荒谬:

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) {
        }
    }

答案 1 :(得分:14)

你考虑过这样的事情:

interface Bar extends Foo, Closeable {
}

然后模拟界面栏?

答案 2 :(得分:11)

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

顺便说一句,我闻到了一些代码wiff - 如果一个方法真的将对象视为两个不同的东西,在这种情况下是FooCloseable接口?

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

以这种方式构造代码使'open'和'close'保持在同一try ... finally块中,并且恕我直言使代码更具可读性,更不用说更通用的方法,并允许您传递仅实现{的对象{1}}。

答案 3 :(得分:5)

most voted answer的替代方案仍然基于 Mockito ,但带有注释。您可以直接从Mock注释设置extraInterfaces作为下一个:

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

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

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

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

答案 4 :(得分:2)

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

示例(来自mockit.ExpectationsUsingMockedTest JUnit 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();
}

DependencyRunnable是接口。 doSomething方法属于第一个,run属于第二个。

答案 5 :(得分:2)

解决此问题的另一种方法是使用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();

这是否是个好主意,需要讨论......