Annotations for EasyMock

Look at this:

@Test
public void shouldDoSomething(){...

With JUnit, that’s all you have to do make a method behave as a test.

It’s clear at first glance that this is a test. That one simple annotation makes the method take on all the characteristics of a test, allows it to participate in test suites, be executed by standard tools, report failures in standard ways, and all the things you have come to expect to happen automatically.

If you’re an EasyMock user, don’t you think it would be nice if you could just use a simple annotation to say “Hey, make this thing a mock, make it behave like a mock, make it do all the things we know mocks are meant to do”, and not have to do it all yourself?

Something like:

@NiceMock
private UserDao userDao;

Wouldn’t that be nice? For one thing, that annotation tells the reader straight away that this is a mock. And if it meant that I don’t have to create the mock, dealing with the differences in creating mocks for interfaces and classes, and have to remember to call verify and so on, well then, that would be great.

Now that I’ve said that this field should behave like a mock, wouldn’t it also be nice if it just filled in where it was needed, without me having to pass it into the test subject?

What if I could just declare which of the fields in my test is actually the test subject, then all the mocks will just go where they fit?

@TestSubject
private Thing somethingThatNeedsTesting;

Well, with EasyMockRule, all of this is possible. EasyMockRule is a JUnit Rule and a few annotations that takes away all the manual drudgery of using EasyMock, and removes all the mocking related clutter from your test classes.

Take a look at this example and see what’s missing. Nowhere is a mock created, injected into the test subject, or verified. It all happens automatically, and the annotations make it immediately clear what purpose each of those fields is fulfilling.

public class SomeTest {

    @Rule
    public EasyMockRule mocks = new EasyMockRule(this); 

    @StrictMock
    private SomeThing aMockedThing;

    @NiceMock
    private SomeThing somethingElse;

    @TestSubject
    private SomeOtherThing theTestSubject;

    @Test
    public void shouldDoSomething() throws Exception {

        expect(aMockedThing.doStuff()).andReturn("stuff").atLeastOnce();

        mocks.replayAll();

        Object result = theTestSubject.doSomethingThatUsesTheMock();

        assertThat(result, is("what you expected"));
    }
}

We can see that one of them is going to be a “Nice” mock and the other will be “Strict”. They were created and injected into the “TestSubject”. I can switch them all into replay mode with one convenience method that means none will accidentally be missed. They were all verified automatically, so I don’t have to do it myself, and it can’t be forgotten.

This is how it should be. I just say that something is a Mock or a NiceMock or a StrictMock, and it just goes away and behaves as a mock should, doing all the things we expect mocks to do. Awesome. And it leaves my test clean and readable and free of all the engineering that was only ever there to make EasyMock work, and was never an important part of the story this test was trying to tell to the reader.

EasyMock Annotations

But there’s more.

When an expectation failure occurs, you get a message like

Expectation failure on verify:
    findAll(): expected: 2, actual: 1

Now go and track down which mock was involved in that call.

But EasyMockRule automatically names your mocks so that you get expectation failure messages that tell you the name of the field:

Expectation failure on verify:
    thingyDao.findAll(): expected: 2, actual: 1

Now you can quickly find that field and work out where it was being used. Sure, you can name mocks that you create manually with EasyMock, but do you do that? Do the people on your team do that? Every time? And even if they do, wouldn’t it be better if it just happened automatically, because it’s a sensible, helpful thing to do that should be a default?

Here’s another way EasyMockRule can help make your tests cleaner. It’s important that tests are as specific as necessary, no more, no less. A test that is too specific is brittle. Changing some part of the implementation that does not matter to the externally visible behaviour will break the test when it shouldn’t. Not specific enough, and subtle changes that have affected correctness will be allowed through when they shouldn’t have been.

One area where it can be difficult to be only as precise as necessary without undue clutter, is in the argument matchers for EasyMock expectation setters.

Coders often make the argument matchers too wide or too narrow, because it’s easy to just write “anyObject()” or “eq(someVariable)”

EasyMockRule has a convenience method to allow using any Hamcrest matcher as an EasyMock argument matcher, so now you can write clean and precise argument matchers with ease, using the “with” method:

expect(something.doStuff(with(hasProperty("name", equalTo(value)))).andStubReturn(result);

expect(something.doStuff(with(hasWhatImLookingFor()))).andStubReturn(result);

    ...

    private Matcher hasWhatImLookingFor() {
        return your-custom-matcher...
    }

EasyMockRule finally gives a solution for annotations in EasyMock, that works, is properly tested, available from Maven Central, open source, well documented, and really easy to use. It’s also very easy to gradually retrofit EasyMockRule to a large existing code base, one test class at a time. Any time you work on an existing test class you simply add the EasyMockRule JUnit Rule instance, add the @Mock and @TestSubject annotations, delete any “createMock” calls, delete all the calls to “replay” and “verify”, add a single call to “mocks.replayAll()”, and delete all the calls that set mocks into the test subject. In other words, you add two lines, a few annotations, and then delete several dozen lines of junk code.

Your tests will be cleaner, and you will spend a lot less time writing them. You’ll never again find that a test was only passing because someone had missed a call to verify one of the mocks.

EasyMockRule is available in Googlecode at

https://code.google.com/p/easymockrule/Annotations for EasyMock

Advertisements
Posted in EasyMock, JUnit

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

%d bloggers like this: