Using JUnit 4 Theories to Test Contracts 5

Posted by Berin Loritsch Tue, 09 Feb 2010 16:08:00 GMT

I’ve been putting off upgrading to JUnit 4 for a while. After all, just how much does it really buy you? It turns out, that JUnit 4 grants you a number of advantages that weren’t available with JUnit 3. One of those features is currently in an experimental phase: Theories. Theories let you specify a bunch of data points, which can be applied to each theory in your class. For example, if you want to test some boundary conditions on a class, you can make it happen easily like this:

@RunWith(Theories.class)
public class VerifyMyAlgorithm {
    @DataPoint
    public static int limLow = 0;

    @DataPoint
    public static int limHigh = 3000;

    @DataPoint
    public static int belowLimLow = limLow - limHigh;

    @DataPoint
    public static int aboveLimHigh = limHigh * 2;

    @DataPoint
    public static int median = (limHigh - limLow) / 2;

    @Theory
    public void verifyTwoParameters(int first, int second) {
        assertInRange(limLow, limHigh, MyMath.algorithm(first,second));
    }
}

I wanted to keep it simple just so you can get the basic idea. Essentially the @RunWith() annotation changes the basic behavior of your test class. It enables the use of the following annotations: @DataPoint, @DataPoints (more on this later), and @Theory. The data points you specified are collected and matched together so that each unique combination of datapoints is applied to the parameters in your theory. If your theory takes one parameter, the theory is run once per data point. If your theory takes two parameters it is run with every unique combination (15 times in this case).

But wait, there’s more! Sometimes we want to generate our datapoints with code. For example, we may need prime numbers up two four significant digits, or we need to initialize our data. In order to do that, we can use the @DataPoints annotation. The return type of your static method will be an array of datapoints. I could rewrite the example above like this:

@RunWith(Theories.class)
public class VerifyMyAlgorithm {
    @DataPoints
    public static int[] attemptLimits() {
        return new int[] {0,3000,-3000,6000,1500};
    }

    @Theory
    public void verifyTwoParameters(int first, int second) {
        assertInRange(limLow, limHigh, MyMath.algorithm(first,second));
    }
}

The DataPoints functionality in concert with the theories are the foundation of what is ncessary to automatically test the contracts of each service. I’ve thrown together a rudimentary class scanner that uses reflection to iterate over classes in the classpath to determine if they match the criteria for the service. For example, you can look at all classes that implement an interface, or extend a base class, or even have an annotation. From that list of classes we can test the contracts of the implementations. The nice aspect of this approach over creating a base test class and extend it manually for each implementation we write, is that it automatically finds the new implementations for you. I have yet to release the class scanner, but you can implement your own pretty well. Here is an example of how it would be used:

@RunWith(Theories.class)
public class EnforceLocakableContracts {
    @DataPoints
    public static Lockable[] collectImplementations() {
        Collection<Class<?>> klasses = new ClassCollector()
                .assignableTo(Locakable.class).recurse().collect();

       Lockable[] implementations = new Lockable[klasses.size()];
       int i = 0;
       for (Class<?> klass : klasses) {
           implementation[i] = klass.newInstance();
           i++;
       }

       return implementations;
    }

    @Theory
    public void lockShouldApplyToOneUser(Lockable lockable) {
        User one = TestSupport.createUser("one");
        User two = TestSupport.createUser("two");

        assertFalse(lockable.isLocked());

        lockable.acquireLock(one);

        assertFalse(lockable.canAccess(two);
    }

    @Theory
    public void lockableShouldBeAccessibleByLocker(Lockable lockable) {
        User one = TestSupport.createUser("test");

        assertFalse(lockable.isLocked());

        lockable.acquerLock(one);

        assertTrue(lockable.canAccess(one);
    }
}

So on and so forth. Just add a new Theory for each aspect of the implementing class you want to test. With this approach, testing implmentations of an interface is essentially future proofinf yourself against lazy programmers. There are some aspects that this approach doesn’t handle well just yet, such as complex setup for each object.

As of JUnit 4.7 there are a few problems, but they are not insurmountable:

  • You see one pass/fail per theory (not per implementation)
  • Failures do not show what implementation failed (fixed in the stacktraces provided by JUnit 4.8.1)
  • The first failure kills future tests. You may have errors in multiple implementations but you won’t be able to find it until you fix the first implementation.

The best thing is to upgrade to JUnit 4.8.1, which is still not available in Maven repositories yet. However, you can also use the System.out approach to find out what the last thing tested was.

There is a feature request for theories to allow you to run them discretely. I.e. each run gets displayed in your test report individually with the parameters supplied in the test name. That will address the shortcomings and make this an even better approach.

What's the purpose of the new iPad from Apple?

Posted by Berin Loritsch Thu, 04 Feb 2010 00:08:00 GMT

No new technology has stirred up consternation like Apple’s new iPad introduced last month since the release of the iPhone. Apple purports that there is a market for something in between a laptop and an iPhone/iTouch. I agree with them on that point; however, the market may or may not jump on the iPad. Time will tell, of course.

In the keynote, Apple compares the iPad to something called a “NetBook”. NetBooks users can be divided into two major camps: people who want a cheap way to do Windows, and people who just want to browse the web and check email. The current NetBook market has offerings with Windows and Linux. They are tiny, have cramped keyboards, and really aren’t that remarkable. The iPad would be a great alternative for folks who don’t care about Windows. But I don’t think that’s the market, really.

Amazon has this thing called a Kindle, and Barnes and Noble has their version of a competing product. The Kindle is pretty cool, it is designed to make reading electronic books an enjoyable pastime. I see commuters with Kindles all the time. The Barnes and Noble device is a direct competitor, and because it doesn’t do a whole lot more, they will have a hard time taking over the Kindle. The good points about the Kindle include battery life an Apple device can only dream of, and a display that is easy on the eyes. I noticed Apple’s new book store app with books you can download. I think Apple is aiming for this market with a vengeance—doing for books what they did to the music industry.

The kindle uses something called “liquid paper” which consumes very little energy and is very easy on the eyes. It’s not backlit, and has a similar contrast to what you get with a regular paper book. The liquid paper only consumes energy when the screen has to change. The downside? Only 16 shades of gray. We haven’t had limitations like that since the Commodore 64. However, for reading it is a superior technology. Because of it, the Kindle can hold a charge for more than a week with normal use. That beats iPad’s 10 hour limit handedly. The very thing that makes viewing pictures and watching movies great on the iPad is what makes reading books for extended periods of time a strain on the eyes. The contrast is too great for comfortable reading.

That said, the iPad’s market is bigger than just replacing the Kindle. Think about a commuter. They hop on a bus, run to a train, and take more than an hour to get to work. Many commuters keep themselves entertained watching movies, playing games, texting, reading, studying, and sleeping. Often times on the train you are lucky if you can sit down. A laptop is just a non-starter in this arena. Smart phones, iPods/iTouches, Kindles, newspapers, and physical books rain supreme. They have an advantage that they can be held with one hand while people are staring at them. The other hand comes in to play if the user is texting or interacting with an app. I think the iPad will work very well in this market.

People need something unobtrusive to take notes with, yet is natural and intuitive to use. Even better would be the ability to have your reference material (Bible, text books, etc.) open so you can reference parts of it in your notes. It’s a matter of time before there’s a really good note taking app for that. The casual internet user will prefer to have something like the iPad than a desktop or laptop hooked up in a room. If you have FiOS, they give you a wireless router in the package. Why not have a couple devices that make good use of it?

Consider going to a meeting where you are presenting. Now, if your iPad has your slide deck you can really limit the amount of cruft you have to take with you. With the right adapter, you can display the slides on a projector or large screen. However, if you forget the connector and you have a small number of people you are briefing, you still have a big enough display to work with. You can at least see your notes while you are presenting.

There’s going to be a lot more uses for this thing that have yet to be imagined. The exciting thing is that Apple has thrown down the gauntlet and created a new platform… again. What people choose to do with it has yet to be seen. The early adopters will be the commuters, and their enthusiasm will infect others.

Apple does consumer devices like this very well. Sure it lacks the ability to run multiple applications at once. It’s not designed for that to begin with. It’s designed for the user who is going to do one thing at a time. Did you notice that the iPhone/iTouch/iPad doesn’t have a window based UI? Each app takes up the full screen. You are supposed to do only one task at a time.

Am I going to buy one when it comes out in March? Maybe not. I’m going to stick with my iTouch until the iPad starts to really define its market.