Mocks are hip when it comes to BDD
I must admit that I rarely spend too much time with Mock objects– I have found in many scenarios that these handy objects get abused and in a few situations, completely invalidate the tests they were designed to facilitate. Plus, with myriad JUnit extension frameworks available, I’ve often found that testing is easier without mocks– for instance, why bother mocking out a data layer when you can just bite the bullet and control the underlying database via DbUnit?
Since attending CITCON last April, however, I’ve been digging deeply into Behavior Driven Development or BDD. If you aren’t familiar with this hip term, don’t fear, it’s rather intuitive and is easy to grasp. Briefly, BDD attempts to provide a common vocabulary that facilitates collaboration between business stake holders and those individuals who take requirements and turn them into working code (something that Fit also attempts to manage). What’s interesting about BDD is that the word “test” essentially disappears– rather than thinking in terms of testing, BDD shifts the focus to behavior or what the system should do.
Interestingly, following this paradigm, code that is used to verify functionality becomes human readable. Don’t get me wrong, by the way, you can make JUnit tests quite readable too; in fact, it is certainly a copasetic practice to name one’s test cases descriptively, such as testFindAllReturnsTwoPersons. But the fact of the matter is that with JUnit (and associated frameworks) you are, in essence, forced to think in terms of testing (regardless if you actually have to name the test case with test– annotations in JUnit 4 and TestNG facilitate flexible naming, man).
Once you accept BDD as a way of thinking, an intriguing thing happens– mocks become quite attractive in the early design a system. Of course, mocks are useful in this context without BDD, TDD, or any other methodology, but the point being, when thinking of behavior, you are forced to think in terms of isolation and interfaces. And because I’m thinking about behavior, I’m not focused on testing (which for some odd reason, appears to be a jive turkey word to developers far too often in my experience).
For example, imagine, because it’s your bag, you’ve been hired to develop an astronomy application for students to explore the relationship between planets and their associated moons (or satellites). In this application, a planetary system can have a collection of moons, each having a series of properties relating to radius, orbital period, and distance from a planet. You can ask a particular planetary system for its closest moon, the fastest orbiting moon, and the biggest moon, to name a few features. The goal of these features is to allow students to understand the relationship between satellite properties and how they affect orbital speeds, etc (for instance, what hip factor contributes to a faster orbital speed?).
Given this high level description, you could potentially flesh out a simple model consisting of two interfaces, namely a PlanetarySystem and a Moon.
public interface IPlanetarySystem {
IMoon fastestOrbitingSatellite();
IMoon closestSatellite();
}
For now, the IPlanetarySystem interface exposes two features and, as you can see, man, a moon has a series of properties one can request.
public interface IMoon {
String getName();
double getOrbitPeriod();
double getDistanceFromPlanet();
double getRadius();
}
As a first pass, I could begin to mock out each object and start to specify behavior, using, for example, the JBehave BDD framework (which also happens to bundle a mocking framework known a Minimock). In fact, using JBehave, I can use its Story framework and flesh out a few details, however, that’s a whole other article. Let’s say I’ve done that and in the process, determined that in order to provide the functionality, for instance, to find the closet satellite, I’ll need to create some Comparator types which will facilitate sorting in a collection. Given that I’ve done that, using BDD, I begin to think in terms of given some context, when something happens, then the system should do something in response.
In the case of obtaining the fastest orbiting satellite:
- given a planet has more than one satellite
- when a student requests the fastest orbiting satellite
- then the system should return the moon whose orbital period is the shortest
Rather than mock out the IPlanetarySystem object, by this point, I can start to actually create an implementation of it. In fact, I’ll focus on the fastestOrbitingSatellite method, which will sort a given collection of IMoons by each moon’s orbital period.
public IMoon fastestOrbitingSatellite() {
IMoon[] sortable = this.getSortableType();
Arrays.sort(sortable, Moon.OrbitPeriodComparator);
return sortable[0];
}
The getSortableType method is a convenience method that was created with the foresight that any sorting style method will need to convert a Collection to an array as shown below.
private IMoon[] getSortableType(){
return (IMoon[])this.moons.toArray(new IMoon[this.moons.size()]);
}
I’d like to verify this behavior, but I haven’t actually created a concrete IMoon object yet other than an anonymous Comparator inner class– Moon.OrbitPeriodComparator, which looks like this:
public static Comparator<IMoon> OrbitPeriodComparator = new Comparator<IMoon>(){
public int compare(IMoon o1, IMoon o2) {
if(o1.getOrbitPeriod() == o2.getOrbitPeriod()){
return 0;
}else if(o1.getOrbitPeriod() > o2.getOrbitPeriod()){
return 1;
}else{
return -1;
}
}
};
Using JBehave’s UsingMiniMock class, I can verify the concrete IPlanetarySystem’s behavior quite easily and keep on truckin’ with a full range of mocking at my disposal. JBehave functions much like JUnit, but instead of each test case starting with “test” a behavioral method starts with “should”– there is also the notion of fixtures via setUp. In my case, I’d like to create a collection of Moon objects, specifically mock moons because I haven’t actually created a concrete instance and I’d like to explore a little bit to ensure I indeed like the intended behavior between a planetary system and a moon.
public class PlanetarySystemBehavior extends UsingMiniMock {
private PlanetarySystem system;
public void setUp(){
IMoon io = this.getMockMoon("Io", 1.77, 422000);
IMoon eur = this.getMockMoon("Europa", 3.55, 671000);
IMoon gan = this.getMockMoon("Ganymede", 7.15, 1070000);
List<IMoon> moons = Arrays.asList(io, eur, gan);
this.system = new PlanetarySystem("Jupiter", moons);
}
}
Thus far, because it’s my bag, I’ve created a Behavior class (via JBehave) that creates a List of IMoons via a getMockMoon method, which handles the nitty gritty of mocking.
private IMoon getMockMoon(String name, double orbitalPeriod, double distance){
Mock moon = mock(IMoon.class);
moon.stubs("getName").withNoArguments().will(returnValue(name));
moon.stubs("getOrbitPeriod").withNoArguments().will(returnValue(new Double(orbitalPeriod).doubleValue()));
moon.stubs("getDistanceFromPlanet").withNoArguments().will(returnValue(new Double(distance).doubleValue()));
return (IMoon)moon;
}
As you can see, Minimock is easy to grasp– I create a mock instance of my interface (IMoon) and then specify the return values for desired methods. In my case, for example, I can specify that the getOrbitPeriod method, when called with no arguments, will return a double value. I then cast the mock into the interface type and return it to the caller so as to avoid any casts later in the process. What a trip!
Now I can verify behavior with a simple method.
public void shouldReturnFastestSatellite() throws Exception{
IMoon moon = this.system.fastestOrbitingSatellite();
ensureThat(moon.getName(), eq("Io"));
}
Note how the method above reads in an agreeable manner– when a student asks for the fastestOrbitingSatellite, the system should return the moon whose orbital period is shortest– in this case, I’m ensuring that the moon’s name is equal to “Io” because I defined it with the shortest value (1.77 earth days).
The beauty of mocks, in this case, is that I’m able to ascertain hip behavior before I even flesh out a concrete class. What’s also helpful is that BDD, in essence, gets me thinking of behavior rather than tests. This difference then has me proactively thinking naturally and thus facilitates the usage of mocks not so much as testing objects but as fleshing out behavior of objects. I can always go back and replace the mocks with concrete objects too– in fact, this sort of iterative design liberates you to throw code away– once things are fleshed out, don’t use the mock– verify the behavior of the real tripping thing, man. And it is in the BDD paradigm that mocks are hip. Dig it?
Tuesday 03 Jul 2007 | Andy | Developer Testing
How do mock objects get invalidate the test cases? I don’t see it. I’ve seen some places where I’ve been tempted to change my code because EasyMock couldn’t handle that particular style, but I’ve not found anything completely killer…
Will- I figured someone would challenge that statement. Far too often when I see mocks being used, they are attempting to break a dependency within code for easier testing, but they dependency they are mocking is the heart of the test. For example, I once ran across a code base where the DAO layer was mocked out for a series of tests. On the surface, not bad and a good use of mocks; however, when I took a look at the DAO layer, it was completely custom with dynamic SQL queries based upon parameters, etc. There weren’t any tests for this layer (except indirect functional ones in later life cycles). So I found myself wondering why a mock layer was produced that ignored the heart of the code base that happened to be where issues usually popped up.
Good post, I’ve been doing BDD lately with TestNG, calling my methods should* and having a small adapter to Hamcrest which makes the asserts more BDD like.
BDD feels more natural than testing for specifying behavior, though I think the level is mostly too low for non-developers, compared to FIT.
Something minor really: why not use o1.getOrbitPeriod().compareTo(…) or Double.compare(…)?
–
Stephan Schmidt :: stephan@reposita.org
Reposita Open Source - Monitor your software development
http://www.reposita.org
Blog at http://stephan.reposita.org - No signal. No noise.
Stephan– using Hamcrest with TestNG for a more BDD style level of verification is an excellent (a.k.a hip) idea. Too bad that you still have to annotate a method with @Test though– perhaps a @Behavior annotation would be interesting as an extension to TestNG (BehaviorNG? :)). Good call on the Fit/BDD non-developers applicability as well– I do think Fit is a bit more helpful in bridging that gap.
I don’t have a really good reason for the use of a
Comparatorother than I wanted to be able to compare any property within anIMoon(assuming there would be more than just shown) and I wasn’t sure of the actual property type– I’m usingdoublenow but I’m wondering if it would be interesting to find a more applicable unit object for Km and earth days, etc.Andy:
With regards to the DAO layer, I think that’s a special case. DAOs (and anything touching the database) are allowed to spit out pretty much anything, at any time, without reference to the underlying logic. The most you can do is specify what data you think it will return, and work with it from there.
How to accurately test a DAO layer has been an issue for me as well. I use Hibernate, so I’ve found it relatively easy to create a small in-memory database and use Hibernate schema creation to create tables, which I can then value with DBUnit. However, I’ve run into issues with constraints and indexes where the Hibernate schema description doesn’t quite match. I’ve heard that some people use Unitils for this, but I can’t comment on its effectiveness.
[…] As I haven’t actually coded a the business class yet, I’ll use JBehave’s mocking library to roughly specify my intended behavior. For example, given what I believe is a good zip code, the validation service should return true and consequently, given a bad zip code, the service should reject it. […]
[…] Because it’s my bag, I happen to agree with this notion (that BDD is TDD done right) but I find that BDD makes it a whole lot easier because it drops the word “test” in favor of “should”. And, as I’ve found, should rolls off the tongue quite naturally, man. Take the simple example of a queue data structure. Imagine someone has asked you to describe one– maybe you’d say something like this (note that I even left out the hip filler words in your favor, baby): A queue is a first in first out data structure. It accepts items via an enqueue method and when dequeue is called, the oldest item (the item who was enqueued before everything else) in the queue should be returned. If dequeue is called on an empty queue, an exception should be thrown; plus, enqueue shouldn’t accept null as a value. […]