是否可以使用 EasyMock 创建一个实现多个接口的模拟对象?
例如,接口Foo
和接口Closeable
?
在 Rhino Mocks 中,您可以在创建 mock 对象时提供多个接口,但 EasyMock 的createMock()
方法只接受一种类型。
是否可以使用 EasyMock 来实现这一点,而无需求助于创建一个同时扩展Foo
and的临时接口,Closeable
然后对其进行模拟?
是否可以使用 EasyMock 创建一个实现多个接口的模拟对象?
例如,接口Foo
和接口Closeable
?
在 Rhino Mocks 中,您可以在创建 mock 对象时提供多个接口,但 EasyMock 的createMock()
方法只接受一种类型。
是否可以使用 EasyMock 来实现这一点,而无需求助于创建一个同时扩展Foo
and的临时接口,Closeable
然后对其进行模拟?
尽管我从根本上同意尼克霍尔特的回答,但我想我应该指出,mockito允许通过以下调用执行您所要求的操作:
Foo mock = Mockito.mock(Foo.class, withSettings().extraInterfaces(Bar.class));
显然,您必须使用演员表:(Bar)mock
当您需要将模拟用作 aBar
但演员表不会抛出时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) {
}
}
你有没有考虑过类似的事情:
interface Bar extends Foo, Closeable {
}
然后模拟界面吧?
EasyMock 不支持此功能,因此您只能使用临时界面的回退。
顺便说一句,我闻到了一点代码的味道——一个方法真的应该把一个对象当作两个不同的东西,在这种情况下是Foo
和Closeable
接口吗?
这对我来说意味着该方法正在执行多个操作,虽然我怀疑其中一个操作是“关闭” Closeable
,但调用代码决定是否需要“关闭”不是更有意义吗?
以这种方式构造代码将“打开”和“关闭”保持在同try ... finally
一块中,恕我直言,使代码更具可读性,更不用说该方法更通用,并允许您传递仅实现的对象Foo
。
投票最多的答案的替代方案仍然基于Mockito但带有注释。您可以extraInterfaces
直接从Mock
注释中设置如下:
@RunWith(MockitoJUnitRunner.class)
public class MyTest {
@Mock(extraInterfaces = Closeable.class)
private Foo foo;
...
}
注意: extraInterfaces
是类型Class<?>[]
,因此您可以根据需要指定多个接口。
如果您需要模拟额外接口的方法调用,则需要强制转换您的模拟。例如,假设我想IOException
在调用close()
mock时抛出一个foo
,相应的代码将是:
Mockito.doThrow(IOException.class).when((Closeable) foo).close();
据我所知,唯一明确支持模拟多个接口的 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
。
解决此问题的另一种方法是使用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();
这是否是一个好主意,这有待讨论......