Возможно ли создать макет объекта, который реализует несколько интерфейсов с помощью EasyMock?
Возможно ли создать макетный объект, который реализует несколько интерфейсов с помощью EasyMock?
Например, интерфейс Foo
и интерфейс Closeable
?
В Rhino Mocks вы можете предоставить несколько интерфейсов при создании макетного объекта, но метод EasyMock createMock()
принимает только один тип.
Возможно ли достичь этого с помощью EasyMock, не прибегая к резервному созданию временного интерфейса, который расширяет как Foo
, так и Closeable
, а затем насмехается над этим?
Ответы
Ответ 1
EasyMock не поддерживает это, поэтому вы задерживаетесь с возвратом временного интерфейса.
В стороне, я чувствую немного кода wiff - должен ли метод действительно обрабатывать объект как 2 разные вещи, интерфейс Foo
и Closeable
в этом случае?
Это означает, что метод выполняет несколько операций, и, хотя я подозреваю, что одна из этих операций заключается в "закрытии" Closeable
, не имеет ли смысл, чтобы вызывающий код решал, закрыть '?
Структурирование кода таким образом сохраняет "открытые" и "закрытые" в одном и том же блоке try ... finally
, а IMHO делает код более удобочитаемым, не говоря уже о более общем методе и позволяет передавать объекты, которые реализуют только Foo
.
Ответ 2
Хотя я принципиально согласен с ответом Ника Холта, я думал, что должен указать, что mockito позволяет делать то, что вы просите, со следующим call:
Foo mock = Mockito.mock(Foo.class, withSettings().extraInterfaces(Bar.class));
Очевидно, вам придется использовать cast: (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) {
}
}
Ответ 3
Считаете ли вы что-то вроде:
interface Bar extends Foo, Closeable {
}
а затем mock interface Bar?
Ответ 4
Альтернатива самого голосованного ответа по- прежнему основана на Mockito, но с аннотациями. Вы можете установить extraInterfaces
непосредственно из аннотации Mock
следующим образом:
@RunWith(MockitoJUnitRunner.class)
public class MyTest {
@Mock(extraInterfaces = Closeable.class)
private Foo foo;
...
}
NB: extraInterfaces
имеет тип Class<?>[]
Поэтому при необходимости вы можете указать несколько интерфейсов.
Если вам нужно высмеять вызовы методов дополнительных интерфейсов, вам нужно будет сделать свой макет. Например, позвольте сказать, что я хочу бросить IOException
когда я вызываю close()
на мой mock foo
, соответствующий код будет тогда:
Mockito.doThrow(IOException.class).when((Closeable) foo).close();
Ответ 5
Насколько мне известно, единственный инструмент для издевательств для 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
- второму.
Ответ 6
Еще один способ решить эту проблему - использовать 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();
Является ли это хорошей идеей, это что-то до обсуждения...