views:

1942

answers:

5

I'm using Mockito to write a unit test in Java, and I'd like to verify that a certain method is the last one called on an object.

I'm doing something like this in the code under test:

row.setSomething(value);
row.setSomethingElse(anotherValue);
row.editABunchMoreStuff();
row.saveToDatabase();

In my mock, I don't care about the order in which I edit everything on the row, but it's very important that I not try to do anything more to it after I've saved it. Is there a good way to do this?

Note that I'm not looking for verifyNoMoreInteractions: it doesn't confirm that saveToDatabase is the last thing called, and it also fails if I call anything on the row that I don't explicitly verify. I'd like to be able to say something like:

verify(row).setSomething(value);
verify(row).setSomethingElse(anotherValue);
verifyTheLastThingCalledOn(row).saveToDatabase();

If it helps, I'm switching to Mockito from a JMock test that did this:

row.expects(once()).method("saveToDatabase").id("save");
row.expects(never()).method(ANYTHING).after("save");
A: 

Can you have your stub call to "save" remove all other expectations?

Nerdfest
In Mockito, verification that methods were called happens after the fact--there are no expectations.
Moss Collum
A: 

Easymock has method org.easymock.EasyMock.expectLastCall

01
+5  A: 

I think it requires more custom work.

verify(row, new LastCall()).saveToDatabase();

and then

public class LastCall implements VerificationMode {
    public void verify(VerificationData data) {
     List<Invocation> invocations = data.getAllInvocations()
     InvocationMatcher matcher = data.getWanted();
     Invocation invocation = invocations.get(invocations.size() - 1);
     if (!wanted.matches(invocation)) throw new MockitoException("...");
    }
}

Previous Answer:

You are right. verifyNoMoreInteractions is what you need.

verify(row).setSomething(value);
verify(row).setSomethingElse(anotherValue);
verify(row).editABunchMoreStuff();
verify(row).saveToDatabase();
verifyNoMoreInteractions(row);
Kent Lai
No it isn't. I've updated the question to clarify why.
Moss Collum
Oh wow. I'd missed your update until I was reviewing old questions just now, otherwise I would have upvoted this sooner. That looks like exactly what I need. Thanks!
Moss Collum
+1  A: 

Have a look at verification in order.

A: 

This question led me to make some enhancements to the Verifications API in JMockit (available in the upcoming release 0.983).

The solution I came up with allows you to write (in a test method):


    new VerificationsInOrder() {{
        unverifiedInvocations();
        row.saveToDababase();
    }};

... if you only want to verify that a certain method is called after everything else. To verify it happens before all other invocations, simply move the call to the top. This actually applies to any sequence of consecutive invocations.

If in addition to the above verification, you also want to verify that some other methods are called in any order, a second verifications block can be added to the test (before or after the other block, it doesn't matter):


    new Verifications() {{
        row.setSomething(value);
        row.setSomethingElse(anotherValue);
    }};

Although a bit long because of the use of anonymous inner classes, this syntax is both simple and flexible; notice how it adds structure to the test and avoids the repetition of method calls (like verify(...)). There is more to it than I described here (Hamcrest matchers, invocation counts, etc.), and it's not limited to the verification of instance methods (static methods and constructors can be mocked and verified in the same way).

Rogerio