使用EasyMock可以创建一个实现多个接口的模拟对象吗?
例如,实现接口 Foo
和接口 Closeable
?
在Rhino Mocks中,您可以在创建模拟对象时提供多个接口,但是EasyMock的createMock()
方法只需要一个类型。
是否可以在EasyMock中实现这一点,而不必采用创建临时接口来扩展 Foo
和 Closeable
接口的回退方案,然后再对其进行模拟?
使用EasyMock可以创建一个实现多个接口的模拟对象吗?
例如,实现接口 Foo
和接口 Closeable
?
在Rhino Mocks中,您可以在创建模拟对象时提供多个接口,但是EasyMock的createMock()
方法只需要一个类型。
是否可以在EasyMock中实现这一点,而不必采用创建临时接口来扩展 Foo
和 Closeable
接口的回退方案,然后再对其进行模拟?
Foo mock = Mockito.mock(Foo.class, withSettings().extraInterfaces(Bar.class));
显然,当你需要将mock用作Bar时,你必须使用转换: (Bar)mock
,但这个转换不会抛出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 {
}
然后模拟接口 Bar?
EasyMock不支持这个功能,所以你只能使用临时接口的回退方法。
另外,我感觉有点代码异味-一个方法真的应该把一个对象视为两个不同的东西吗?在这种情况下是Foo
和Closeable
接口?
这让我觉得这个方法正在执行多个操作,虽然我猜想其中一个操作是“关闭”Closeable
,但是是否需要“关闭”由调用代码决定不更好吗?
这样构造代码可以将“打开”和“关闭”保留在同一try ... finally
块中,使代码更易读,而且这个方法更通用,可以传递实现Foo
接口的对象。
getFirstName()
、getAddress()
等)的接口Person
,以及仅包含setter(例如setFirstName()
、setAddress()
等)的接口ModifiablePerson
时,您想要测试一个SUT,它需要Person
,但会检查传递的对象是否为ModifiablePerson
的实例,并根据此做一些操作。Closeable
也是一个很好的例子:如果对象提供了“扩展”功能,并且通过instanceof
进行了显式检查并得到利用,那么这有什么不好呢? - dma_k一个基于Mockito,使用注释的最佳答案替代方案(原回答被点赞最多)。您可以从Mock
注释直接设置extraInterfaces
如下:
@RunWith(MockitoJUnitRunner.class)
public class MyTest {
@Mock(extraInterfaces = Closeable.class)
private Foo foo;
...
}
注意:extraInterfaces
是 Class<?>[]
类型的,因此您可以根据需要指定多个接口。
如果您需要模拟额外接口的方法调用,则需要对模拟对象进行强制类型转换。例如,假设我想在调用模拟对象 foo
的 close()
方法时抛出 IOException
,则相应的代码如下:
Mockito.doThrow(IOException.class).when((Closeable) foo).close();
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
的方法。
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();