The phantom mock

A couple of days ago, a co-worker came by with an interesting problem.  His unit test class was failing, with a mock saying that it got more calls to a certain method than it had been set up to expect.

The odd thing was, the test class we were looking at didn’t declare any mocks!

A Clue

The failing test class passed when run by itself, failing only when run with the rest of the module’s unit tests…

The Problem

The problem turned out to be that a test class that ran earlier in the test run was injecting a mock into a singleton and not cleaning up after itself.  The singleton was later used by the failing test, which unwittingly made use of the mocked guts of the singleton, resulting in the unmet expectations.

A Solution

The offending test just needed to reset the guts of the singleton back to its normal, non-mocked value in its @After or @AfterClass method.


It seems to me it would be even better to implement the singleton using a factory, to avoid such side-effects popping up in the future (see StartupSvcFactory: why go to the bother? for some discussion about factories and singletons).  True, there’s the extra conceptual overhead of one more (factory) class and two more interfaces — but I think the resulting cleanness of the test code makes it worth it, at least if you ever need to mock what the singleton provides (as we did in this example).

I thought they were out to get me

First, some background:

Keith just recently changed our can’t-mock-dis Startup service from a plain ol’ Singleton (in the Gang-of-Four sense, not in the Spring sense) to an Abstract Factory so that — woohoo! — we can now mock out the Startup service and its application-context-creatin’ slowness when we want to.

This gives us such great flexibility in the testing department, and the cost is a slightly wordier syntax when you’re getting an instance of the real StartupSvc.  This syntax changed from:

StartupSvc startupSvc = StartupSvc.getStartupSvc();


StartupSvc startupSvc = new StartupSvcFactoryImpl().getStartupSvc();

But these calls aren’t littered throughout the application code — it’s kicked off by ServletContextListeners and such — so there are really only a few places that even have to change.  It’s great!

A Happy Move

So anyway, earlier this week when Keith committed his changes, I had eventually Maven Eclipsed a couple of prototype .war projects I was working on and noticed that I needed to update to the new syntax for getting an instance of the StartupSvc.  I was glad to see that the abstract factory stuff had been committed.

But then today, I Maven Eclipsed again, and now Eclipse was saying it didn’t know what a StartupSvcFactoryImpl was and trying to get me to return to the old syntax.

Reversion Revulsion

It appeared that Keith had reverted his changes and removed the abstract factory.  Had he encountered a nasty problem and reverted it until we could figure out a solution?  I didn’t want to go back to the old way!  Why didn’t he tell me?!  (This last one was a bit hypocritical on my part, since I’m not very good yet myself at noticing when my changes are breaking changes that will affect others on the project and notifying them accordingly.)

Silly Me

Then I realized that, oops, hadn’t I just Maven Install’d the Startup module (with a minor change I needed to test with on my other project) to my local Maven repository from my local working copy?  And how long had it been since I had updated the source code of that project?

Oopsy oops, I had just made the StartupSvc revert, by installing an older version.  I just updated the Startup project from Subversion, then Maven Installed it again, then Maven Eclipsed my .war prototype… and the abstract factory is back.

Silly me!  :)