I’m trying to write a unit test (using JMockit) that verifies that methods are called according to a partial order. The specific use case is ensuring that certain operations are called inside a transaction, but more generally I want to verify something like this:
- Method
beginTransaction
is called. - Methods
operation1
through tooperationN
are called in any order. - Method
endTransaction
is called. - Method
someOtherOperation
is called some time before, during or after the transaction.
The Expectations and Verifications APIs don’t seem to be able to handle this requirement.
If I have a @Mocked BusinessObject bo
I can verify that the right methods are called (in any order) with this:
new Verifications() {{ bo.beginTransaction(); bo.endTransaction(); bo.operation1(); bo.operation2(); bo.someOtherOperation(); }};
optionally making it a FullVerifications
to check that there are no other side-effects.
To check the ordering constraints I can do something like this:
new VerificationsInOrder() {{ bo.beginTransaction(); unverifiedInvocations(); bo.endTransaction(); }};
but this does not handle the someOtherOperation
case. I can’t replace the unverifiedInvocations
with bo.operation1(); bo.operation2()
because that puts a total ordering on the invocations. A correct implementation of the business method could call bo.operation2(); bo.operation1()
.
If I make it:
new VerificationsInOrder() {{ unverifiedInvocations(); bo.beginTransaction(); unverifiedInvocations(); bo.endTransaction(); unverifiedInvocations(); }};
then I get a “No unverified invocations left” failure when someOtherOperation
is called before the transaction. Trying bo.someOtherOperation(); minTimes = 0
also doesn’t work.
So: Is there a clean way to specify partial ordering requirements on method calls using the Expectations/Verifications API in JMockIt? Or do I have to use a MockClass
and manually keep track of invocations, a la:
@MockClass(realClass = BusinessObject.class) public class MockBO { private boolean op1Called = false; private boolean op2Called = false; private boolean beginCalled = false; @Mock(invocations = 1) public void operation1() { op1Called = true; } @Mock(invocations = 1) public void operation2() { op2Called = true; } @Mock(invocations = 1) public void someOtherOperation() {} @Mock(invocations = 1) public void beginTransaction() { assertFalse(op1Called); assertFalse(op2Called); beginCalled = true; } @Mock(invocations = 1) public void endTransaction() { assertTrue(beginCalled); assertTrue(op1Called); assertTrue(op2Called); } }
Advertisement
Answer
if you really need such test then: don’t use mocking library but create your own mock with state inside that can simply check the correct order of methods. but testing order of invocations is usually a bad sign. my advice would be: don’t test it, refactor. you should test your logic and results rather than a sequence of invocations. check if side effects are correct (database content, services interaction etc). if you test the sequence then your test is basically exact copy of your production code. so what’s the added value of such test? and such test is also very fragile (as any duplication).
maybe you should make your code looks like that:
beginTransaction() doTransactionalStuff() endTransaction() doNonTransactionalStuff()