views:

994

answers:

4

Is it possible to create a mock object that implements several interfaces with EasyMock?

For example, interface Foo and interface Closeable?

In Rhino Mocks you can provide multiple interfaces when creating a mock object, but EasyMock's createMock() method only takes one type.

Is it possbile to achieve this with EasyMock, without resorting to the fallback of creating a temporary interface that extends both Foo and Closeable, and then mocking that?

A: 

have you considered something like:

interface Bar extends Foo, Closeable {
}

and then mock interface Bar?

extraneon
Yes, I was just seeing if I could avoid that. Per my question: "Is it possbile to achieve this with EasyMock, without resorting to the fallback of creating a temporary interface that extends both Foo and Closeable, and then mocking that?"
Daniel Fortunov
+4  A: 

EasyMock doesn't support this so you're stuck with fallback of the temporary interface.

As an aside, I smell a little bit of a code wiff - should a method really be treating an object as 2 different things, the Foo and Closeable interface in this case?

This implies to me that the method is performing multiple operations and while I suspect one of those operations is to 'close' the Closeable, wouldn't it make more sense for the calling code to decide whether or not the 'close' is required?

Structuring the code this way keeps the 'open' and 'close' in the same try ... finally block and IMHO makes the code more readable not to mention the method more general and allows you to pass objects that only implement Foo.

Nick Holt
I agree with this, but to expand: if you are using dependency injection, and your class needs both a Foo and a Closable, you should really have two separate setters for those. If you choose to inject the same object for both of these, then great, but I think the class-under-test doesn't need to know that they are the same object - it should treat the Foo as a Foo and the Closeable as a Closeable
matt b
Nick, Matt, thanks for your input. Just to clarify the scenario, the context is that Foo is an interface for a modular add-in system. Third-party modules implement Foo and are then instantiated and used by the framework. They can also optionally implement Closeable, in which case the framework will close them when it has finished using them. Hence, the unit tests need to cover two distinct scenarios: A Foo which is also Closeable, and a Foo which is not Closeable. I hope this makes sense.
Daniel Fortunov
+1  A: 
Rogerio
This snippet does not seem to create the mock object. How would you do that ?
Thomas Dufour
The test above works for me. Did you try running it?
Rogerio
+1  A: 

Although I fundamentally agree with Nick Holt's answer, I thought I should point out that mockito allows to do what you ask with the following call :

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

Obviously you'll have to use the cast: (Bar)mock when you need to use the mock as a Bar but that cast will not throw ClassCastException

Here is an example that is a bit more complete, albeit totally absurd:

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