是否可以创建一个使用EasyMock实现多个接口的模拟对象?
例如,界面Foo
和界面Closeable
?
在Rhino Mocks中,您可以在创建模拟对象时提供多个接口,但EasyMock的createMock()
方法只需要一种类型。
是否有可能使用EasyMock实现这一点,而不是依靠创建一个扩展Foo
和Closeable
的临时接口的后备,然后嘲笑它?
答案 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 - 如果一个方法真的将对象视为两个不同的东西,在这种情况下是Foo
和Closeable
接口?
这对我来说意味着该方法正在执行多个操作,而我怀疑其中一个操作是“关闭”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();
}
Dependency
和Runnable
是接口。 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();
这是否是个好主意,需要讨论......