EasyMock expectation(EasyMock.expect) flavours explained

The EasyMock  framework for unit testing is quite powerful and has loads of mocking APIs for all purposes. One of the most important APIs for mocking is the createMock API. Using this we can create mock objects for a specified interface and then record and verify the method calls. Events are recorded in the IExpectationSetters, which can be created by the EasyMock.expect API. After creating the IExpectationSetters we can set the returned result/calling behavior using the different options available.

Here I have taken an example of a car having an Engine and will try to show you the different kinds of expectation options available.

class Car {
    Engine engine;
    public boolean start() {
         return engine.powerUp();
    }
    public void checkStatus() {
        engine.checkEngineOil();
    }
 }

interface Engile {
    boolean powerUp();
    void checkEngineOil();
}

Now I want to unit test my car, so what are my options ?

Option One: Only Expect and Nothing to Return

Here we want to test the call i.e. if the required method gets called. So we create the mock and just set the expectation of the call, rewind it and then verify it.

@Test
 public void testExpectWithNoReturn() {
 Car car = new Car();
 Engine engine = EasyMock.createMock(Engine.class);
 engine.checkEngineOil();
 EasyMock.replay(engine);
 car.engine = engine;
 car.checkStatus();
 EasyMock.verify(engine);
 }

In the above example we want to see if the checkstaus API calls the checkEngineOil method or not and nothing byond that. You can do this only with methods that return void. If the method that is being called returns something, according to the signature, then you will be required to use one of the other varients.

Option Two: Expect and Return

This option is what most of us use to set the expectation, using the andRetrun API. We create an expectation that returns an object that is similar to what an actual call can return.

@Test
 public void testExpectAndReturn() {
 Car car = new Car();
 Engine engine = EasyMock.createMock(Engine.class);
 EasyMock.expect(engine.powerUp()).andReturn(true);
 EasyMock.replay(engine);
 car.engine = engine;
 assertTrue(car.start());
 EasyMock.verify(engine);
}

Here we are setting the expectaion of engine.powerUp call to retrun true when called and then verifying it later that is gets called.

In the previous option we had an issue if we were required to test a call to a method that return something. We can use this expect and return option to test such case. Since in such cases we are just testing the call so we can return null as result in such mocked calls.

Option Three: Expect and Answer

Suppose we want to perform some operation in our tests on the call how can we do it ?

We will prepare an Answer that will be called when the call takes place. The answer is of type IAnswer interface. It has  an answer method that should be overridden to provide our desired implementation.

@Test
 public void testExpectAndAnswer() {
 Car car = new Car();
 Engine engine = EasyMock.createMock(Engine.class);
 IAnswer jetPropelledEngine = new IAnswer() {
     public Boolean answer() throws Throwable {
          System.out.println("powered by JetPropelled fuel engine");
          return false;}
    };
 EasyMock.expect(engine.powerUp()).andAnswer(jetPropelledEngine);
 EasyMock.replay(engine);
 car.engine = engine;
 assertFalse(car.start());
 EasyMock.verify(engine);
 }

Option Four: Expect and Delegate

As the name suggests the delegate can be used to delegate the call the another object. But there are a few catches here. First, the object should implement the same interface, as the one which gets called. Second, the interface should be a public interface.

This method internally uses the Answer method and reflection to delegate the call to the required interface. In order to work with reflection you need to expose your interface else the EasyMock package will not be able to find it. So the current example will not work unless we make the interface public.

@Test
 public void testExpectAndDelegate() {
 Car car = new Car();
 Engine engine = EasyMock.createMock(Engine.class);
 EasyMock.expect(engine.powerUp()).andDelegateTo(new Crdi());
 EasyMock.replay(engine);
 car.engine = engine;
 assertTrue(car.start());
 EasyMock.verify(engine);
 }

class Crdi implements Engine {
    public boolean powerUp() {
       System.out.println("CRDI engine Rocks");
     return true;
 }}

public interface Engine {
    public boolean powerUp();
}

Here we have made the interface as public but out Crdi class is still not exposed. The call to the engine gets delegated to the Crdi object in this test case.

Option Five: Expect and Throw

This options works just like the “Expect and Return” option. The call is expected but instead of returning a result an exception is thrown.

@Test(expected = RuntimeException.class)
 public void testExpectAndThrow() {
 Car car = new Car();
 Engine engine = EasyMock.createMock(Engine.class);
 EasyMock.expect(engine.powerUp()).andThrow(
 new RuntimeException("Too Hot to handle!!!"));
 EasyMock.replay(engine);
 car.engine = engine;
 assertTrue(car.start());
 }

These are the primary options available in the IExpectationSetters interface. There are some more stub variants of these options. All of these offer loads of functionalities that can be used at many places in most of the unit tests for an application.

About these ads

6 responses

  1. Hello,

    What would you do, if:

    EasyMock.expect(engine.powerUp()).andReturn(true);

    engine.powerUp() would be a void,too?

    Greets,

    Laszlo

    1. Hi Laszlo,

      void method do not return, you just expect the call

      engine.powerup() // if it is void

      Rahul

  2. great article.
    But it’s be even better if you show how to handle method parameters.

    1. EasyMock is a robust API and offers everything, so I split argument matching is a separate blog. Have a look at easymock-assert-arguments-of-method-call and let me know if it helps.

      regards,
      Rahul

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: