Using The New Mockito Annotations

March 9th, 2010 by James Carr

It’s only been a few days since the Mockito 1.8.3 release and I have to say that for a minor release there’s a lot I like about it!

What I like about the new annotations is the ability to have test cases that are completely free of @Before. Observe this example of a class that takes a text input string, translates it to an AuctionEvent, and fires it off to an AuctionEventListener:

@RunWith(MockitoJUnitRunner.class)
public class AuctionMessageTranslatorTest {
	@Mock AuctionEventListener listener;
	@InjectMocks AuctionMessageTranslator translator = new AuctionMessageTranslator();

	@Test
	public void shouldSendAnEventToTheListener(){
		translator.sendMessage("SOL Version: 1.1; Event: PRICE;");

		verify(listener).handleEvent(any(AuctionEvent.class));
	}
}

This is a first step, to just verify an event is passed to the listener (we don’t care about it’s contents yet). @Mock creates a mock on each test method run, and @InjectMocks will pass mocks to any matching setters or constructors.

Now I’ll implement a little code to make the example pass.

public class AuctionMessageTranslator {
	private AuctionEventListener listener;
	public void setListener(AuctionEventListener listener) {
		this.listener = listener;
	}

	public void sendMessage(String message) {
		listener.handleEvent(new AuctionEvent());
	}
}

Doesn’t do much… so let’s add a new example that verifies the contents of the message sent to the listener. Since this object is created by the translator (translating a string to an object) we’ll use an argument captor to capture and verify it’s value.

@RunWith(MockitoJUnitRunner.class)
public class AuctionMessageTranslatorTest {
	@Mock AuctionEventListener listener;
	@Captor ArgumentCaptor<AuctionEvent> arg;
	@InjectMocks AuctionMessageTranslator translator = new AuctionMessageTranslator();

	@Test
	public void shouldSendAnEventToTheListener(){
		translator.sendMessage("SOL Version: 1.1; Event: PRICE;");

		verify(listener).handleEvent(any(AuctionEvent.class));
	}

	@Test
	public void shouldSendAnEventWithNamePrice(){
		translator.sendMessage("SOL Version: 1.1; Event: PRICE;");

		verify(listener).handleEvent(arg.capture());

		assertThat(arg.getValue().getName(), equalTo("PRICE"));
	}
}

It fails, so we implement the code to make it pass:

	public void sendMessage(String message) {
		listener.handleEvent(parseEvent(message));
	}

	private AuctionEvent parseEvent(String message) {
		AuctionEvent auctionEvent = new AuctionEvent();
		auctionEvent.setName(message.split(";")[1].split(":")[1].trim());
		return auctionEvent;
	}

This passes as the argument passed to the listener does indeed contain the event name. This is a little ugly, so let’s refactor it a little bit with our test providing a nice safety net:

	public void sendMessage(String message) {
		listener.handleEvent(parseEvent(message));
	}

	private AuctionEvent parseEvent(String message) {
		AuctionEvent auctionEvent = new AuctionEvent();
		auctionEvent.setName(unpackMessage(message).get("Event"));
		return auctionEvent;
	}

	private Map<String, String> unpackMessage(String message) {
		Map<String, String> pairs = new HashMap<String, String>();
		for(String pairString : message.split(";")){
			String[] pair = pairString.split(":");
			pairs.put(pair[0].trim(), pair[1].trim());
		}
		return pairs;
	}

Looks good, and the test case for it is pretty clean although it has a lot of annotations. We could change the injection strategy to use constructor injection since we don’t really want the object to even exist without a listener:

@RunWith(MockitoJUnitRunner.class)
public class AuctionMessageTranslatorTest {
	@Mock AuctionEventListener listener;
	@Captor ArgumentCaptor<AuctionEvent> arg;
	@InjectMocks AuctionMessageTranslator translator = new AuctionMessageTranslator(listener);
...
}

As long as the @InjectMocks annotation is present, the MockitoJunitRunner will initialize the mocks do they’re available for injection. Drop the @InjectMocks annotation off, and it fails with a null pointer exception.

One interesting thing of note when using @InjectMocks with setter injection is if you do something silly like the following:

@RunWith(MockitoJUnitRunner.class)
public class AuctionMessageTranslatorTest {
	@Mock AuctionEventListener listener;
	@Mock AuctionEventListener listener2;
	@Captor ArgumentCaptor>AuctionEvent> arg;
	@InjectMocks AuctionMessageTranslator translator = new AuctionMessageTranslator();
	...
}

It will inject the first @Mock, not the second. Verifications against listener will work, while verifications against listener2 will fail as it was never injected.

Tomorrow I’ll include some examples of using the @Spy annotation as well as the different answer types you can configure @Mock annotated mocks with as of 1.8.3. ;)

Another Good Tidbit from GOOSGBT

March 9th, 2010 by James Carr

I’m currently in chapter 12 of Growing Object Oriented Software Guided By Tests and thought I’d share another good tidbit from one of the asides:

Put Tests in a Different Package

We’ve adopted a habit of putting tests in a different package from the code they’re exercising. We want to make sure we’re driving the code through its public interfaces, like any other client, rather than opening up a package-scoped back door for testing.

Good point! Almost everytime I’ve found my self expose a method that should be private as protected or default it’s been because that method was really in gross violation of Single Responsibility Principle and I’ve often taken such code and extracted it to a separate object.

Thoughts?

Mockito 1.8.3 Released

March 8th, 2010 by James Carr

Szczepan has announced on the Mockito user mailing list that 1.8.3 of Mockito has been released. This released includes several small (but useful) additions as well as bug fixes.

The two parts of this release I like are the new annotations @Spy, @Captor, and @injectMocks. These add to the already useful @Mock annotation to simplify test setup tremendously. Additionally, the @Mock annotation is now configurable so you can add different Mock/Stub styles; previously @Mock only supported the default mock behavior, now you can configure it to RETURNS_MOCKS, CALLS_REAL_METHODS, etc.

This release also includes a feature I requested that can be useful when trying to get legacy code under test, something I call deep stubs. Ever been in the situation where you have code with something like this in the middle of it:

someCollaborator.getFoo().doBarThings().getBaz().execute().processResult();

Normally to stub this call, you’ll have to mock every object returned by each method call, and then stub the last one. Examples for code like this can be a little verbose, but now you can just @Mock the aggregate root and do something like:

given(someColllaborator.getFoo().doBarThings().getBaz().execute().processResult).willReturn(resultObject);

Just remember friends, this is only good for legacy code… if you are already writing your code exemplar first to drive your design, you should know better than to make your object know too many details about it’s neighbors. :)

This release also includes a patch I submitted to stop having all of the examples in a test run when trying to run a single one in eclipse and intelliJ when using MockitoJunitRunner.

For a complete list of features/fixes, see the release notes.

Scala specs + Mockito == Dead Sexy Examples

February 24th, 2010 by James Carr

Been doing some fooling around with scala for a little bit tonight, and specifically been trying out the BDD framework specs. specs adds some nice stuff to mockito that makes it read like a natural language… and I like it!

Take this simple example of stubbing:

list.get(0) returns "yo"

Yep… that’s perfectly valid scala code… and totally awesome. :)

Want to verify that a method was invoked with a specific argument?

notifier.send(order) was called

And again yes, that is a real line of code pulled from one of my examples. Take a look at more here.

links for 2010-02-20

February 20th, 2010 by James Carr

Sometimes It’s Good To Fail an Interview

February 7th, 2010 by James Carr

Wow… sometimes memories sprout up out of nowhere, and tonight while painting the kitchen I was reminded of my first programming job interview waaaay back in 2003. See I had picked up a few pamphlets at the university career fair and landed a job interview with one of the few (or was it only?) firms offering a computer science related job there. So I dressed up with a tie, made sure I made three copies of my resume on expensive ass paper, put them in a fancy leather folder and headed off to the interview with my fingers crossed.

As I sat through the interview, I went through the usual motions of answering their questions about my background, listened to their marketing talk about how great their company is, and I chatted a bit about my hobbyist programming I did in my free time. Then came the bad news…. the interviewer smiled as he mulled over my resume, and he said he noticed that I didn’t have any COBOL experience. He asked me if I had ever taken any COBOL classes at the college, and I told him no… as far as I know they don’t even have it in the curriculum anymore.

“Really?” he replied, with a slight look of shock on his face. “Well, all of our systems are written in COBOL here, so that’s what you’d be developing in. We really need someone with COBOL experience.”

“Well, I pick up languages pretty quick… I just learned python last week and was able to do all kinds of things with it… I probably wouldn’t have any problems learning COBOL and actually using it.” I replied.

He smiled. “Well, that’s great James. I’ll tell you what, I’ll talk with the rest of my staff and I’ll try and get back with you by the end of the week to let you know if you made it in.”

And I never ever heard from them again. Another guy at my university, who had made straight As in CompSci and double majored in Mathematics got hired out there the following week, so I guessed maybe I just didn’t have a high enough GPA to meet their standards. I remember wondering what was so special about the language… I looked around online and the examples I found were pretty ugly and I remember wondering if it was some kind of joke? But I did hear from the guy who got the job out there that yes… all they programmed in was COBOL.

Looking back, I’m damn happy I never got the job. A large part of my growth was working for a small start up firm and getting the chance to work with all kinds of languages as well as do a lot of reading online to self-teach myself (I didn’t have any senior developers to work with… just me at first) that led me to read books like Design Patterns, Patterns of Enterprise Application Architecture, Refactoring, and even Extreme Programming Explained as I searched for a methodology to manage our projects. With no one to turn to, I often sought help in online forums, mailing lists, and usergroups in St.Louis. I think all of that played a large part in growing as a developer and evolving my thinking.

If I had gotten that job, I probably would have done my best to excel at it… and perhaps by now I would have been promoted to the position Programmer Analyst II. :)

links for 2010-02-05

February 5th, 2010 by James Carr

Running a Single Class From Gradle

February 5th, 2010 by James Carr

Whew… been learning a lot about gradle this evening, and I definitely like it. I’ll expand further with an in depth example, but for now just wanted to post a quick solution to something I was attempting to do. See, I wanted to be able to just type gradle run and have it run a single class from my project, but for some reason was having a difficult time figuring out how to make it work.

Luckily, gradle includes practically all the ant tasks so you can simply use ant.java:

task run(dependsOn:'build') <<{
        ant.java(classname: 'org.jamescarr.Main', fork: true,
        classpath: "${sourceSets.main.runtimeClasspath.asPath}")
}

We want it to depend on the build task so it will compile our classes and dependencies, then it’ll work as expected. :)

A Word About Forced “Agile”

February 3rd, 2010 by James Carr

There’s something that’s been on mind lately from my experiences in the “enterprise” world while contracting… something that’s been really eating at me. And it’s something I’d like to call “Forced Agile” and how it’s possibly the most destructive beast in our industry right now.

The symptoms are quite visible in any organization… different values, practices, and concepts that we use in the agile world for improving our teams are bastardized and turned against the team in the form of forced metrics that are required to be met. This doesn’t help the team one bit and honestly will simply cause the team much grief and do diddly squat to improve anything.

Four years ago I listened to Dave Thomas give a pretty good presentation on Cargo Cults and I’m now realizing something… most companies continue to use the cargo cult approach to adopting agile. They’ve bought into the silly idea that if you do X, Y and Z software will get released faster with zero defects. We’re better than that, and our industry deserves better than that.

Let’s drop this idea of agile being “a set of practices” to be strictly followed. If we really want to succeed at agile we first need to empower our teams to succeed. :)

In The Wild: Mockito for Javascript

January 30th, 2010 by James Carr

Yes it’s true… there in is a framework that acts just like mockito for javascript: jsMockito!

The stubbing action looks pretty cool, and I’ll try in depth later when I’m home. But here’s a quick sample to whet your appetite:

    var mockedObject = mock(Array);

    when(mockedObject).get(1).thenReturn("hello world");