Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I mock a method using EasyMock

User getUser(int id) {
    User user = service.get( id );
    if( user != null ) {
        user.Stuff = getUserStuff( id );
        return User;
    }

    throw new NotFoundException();
}

Stuff getUserStuff( int id ) {
    stuffGetter.getStuff( id ); // stuff getter makes a rest call
    return Stuff;
}

Using EasyMock, how would i test the getUser(id) method. The confusing part for me is that getUserStuff(id) makes an external call which I dont want to make when testing getUser.

like image 731
robasta Avatar asked Jun 19 '14 09:06

robasta


1 Answers

As mentioned by other users in the comments, you need to provide mock instances of the objects that are making the calls that you wish to mock out.

So within getUser(id) I can see a call to an object called service which should be mocked out. So use a mock instance of the service class and then the call to get(id) can be mocked out.

Then within the getUserstuff(id) method, it uses a stuffGetter object which could be mocked out again. Then the method being called could have expectations set up for it. (An alternative to this could also be to set up a partial mock and mock the getUSerstuff(id) method all together, but this is a bit beyond what you're looking to do I think)

With those things in mind, I created the following class to test your described use case:

public class ClassToTest {

    private final Service service;
    private final StuffGetter stuffGetter;

    public ClassToTest() {
        this( new Service(), new StuffGetter() );
    }

    public ClassToTest(final Service service, final StuffGetter stuffGetter) {
        this.service = service;
        this.stuffGetter = stuffGetter;
    }

    public User getUser(final int id) {
        final User user = this.service.get( id );
        if( user != null ) {
            user.stuff = getUserStuff( id );
            return user;
        }

        throw new NotFoundException();
    }

    public Stuff getUserStuff( final int id ) {
        return this.stuffGetter.getStuff( id );
    }
}

Having the constructors set up like this gives me the ability to set up mock instances of the dependencies within the tests. So what follows is a test for the getUser(id) method that uses mocks for the two objects. It uses the basic EasyMock concepts of expect, replay and verify.

  • Create mock instances for the objects you need to mock the method calls on, in this case the service and the stuffGetter.
  • Write expectations for the method calls using the expect method. This is where you specify what will be returned if the method you are mocking is not a void method.
  • Replay the mock objects, in this case replay both of them. This means you can no longer add any expectations because the mocks are no longer in record mode for recording expectations.
  • Execute your tests.
  • Verify that the expected method calls on your mocks were executed as desired.

The tests looks like this:

import static org.junit.Assert.assertEquals;

import org.easymock.EasyMock;
import org.junit.Test;

public class ClassToTestTest {

    @Test
    public void thatGetIdCallsExpectedMockMethods() {
        final User user = new User();
        final Stuff userStuff = new Stuff();

        final Service mockService = EasyMock.createMock(Service.class);
        final StuffGetter mockStuffGetter = EasyMock.createMock(StuffGetter.class);

        EasyMock.expect( mockService.get(15) ).andReturn( user );
        EasyMock.expect( mockStuffGetter.getStuff(15) ).andReturn( userStuff );
        EasyMock.replay( mockService, mockStuffGetter );

        final ClassToTest classToTest = new ClassToTest( mockService, mockStuffGetter );
        final User returnedUser = classToTest.getUser(15);
        assertEquals(returnedUser, user);
        assertEquals(returnedUser.stuff, userStuff);

        EasyMock.verify( mockService, mockStuffGetter );
    }
}
like image 62
Dan Temple Avatar answered Sep 19 '22 20:09

Dan Temple