Clovering Clover

# 2003-03-11 13:22:48 -0500 | Java | 5 Comments

Preamble/Disclaimer

  • Clover 1.1 has been released.
  • I work for Cortex, the company that makes Clover.

About Clover

Clover is a code coverage tool, which you can use to examine how much of your code gets executed when you run your unit tests. This may not seem very interesting to you; so think about these statements before and after running Clover:

Before: “Oh, our unit tests are pretty good.”
After: “Oh dear; our unit tests are only touching 20% of our code base.”

Before: “Oh, our unit tests are pretty good.”
After: “What? 40% of our unit tests aren’t running. Oh, we misconfigured Ant in our continuous-integration environment.”

Before: “We don’t know how good our unit tests are. We have the green bar of goodness; but we do occasionally find bugs that our tests didn’t detect.”
After +0: “Okay, we can now see exactly what we are not testing, lets put some tests here, here and here.”
After +1: “Oh. Those new tests caused red-bar; better fix those bugs.”
After +2: “Got green-bar again, and our coverage is on the rise. Addicted.”

Clovering Clover

So, as you might imagine, the Clover development team uses Clover when running the Clover unit tests. This is “eating our own dog food”.

mlq: I’m writing a blog about clover… will be interesting (hopefully): clovering clover
obj: eating your own dog food - I like it
obj: interesting - I have to keep rejecting (or fixing) patches for Checkstyle, because they do not pass Checkstyle

So, OJB ensures that Checkstyle passes Checkstyle; but Clovering Clover is not that easy.

As part of it’s job, Clover needs to instrument the source code it is going to be measuring. Then, at runtime, a class called CloverRecorder is used to keep the tally of method, statement, etc. counts. When each instrumented class is initialised in the JVM, a CloverRecorder is configured for it (using a static variable, usually).

Now, when we are Clovering Clover, we naturally instrument CloverRecorder. So, at runtime, as the CloverRecorder class gets initialised, it needs to configure a CloverRecorder. But that class isn’t finished loading yet! By Clovering Clover, we introduce a circular initialisation problem.

(The above explanation is a slightly simplified version of how Clover actually works; the point is that Clovering Clover causes some mind-bending circular dependencies!)

We came up with a fairly fun fix to this problem (which I have just spent the last day fine tuning). First, we build Clover the good old-fashioned way (and we quickly run the unit tests the old-fashioned way, too). This is our “real” Clover.

We then copy all the source (including unit tests) to a temp directory and use Ant’s <replace> to rename all the package/import statements from com.cortex... to repackaged.com.cortex…. We compile this source using the “real” Clover, and run the “pretend” unit tests over the “pretend” code. There are no circular dependencies, since there are no relationships between the “real” code and the “pretend” code; they are disjoint.

Sometimes coding isn’t just about lines of code; it’s about bending your mind and bending it back again.

5 Responses to this entry:

  1. Oliver Burn Says:

    Great article - but I do not understand why you need "pretend" unit tests. Is it because your tests require access to package protected types/methods?

  2. Matt Quail Says:

    Oliver, the reason why we have "pretend" unit tests is
    that it is just simpler.

    Currently, our unit tests are in the same "package" as the
    class they test (though they are in different source tree).
    Therefore, they don’t need to import the class being tested.
    Now, if we re-packaged the code but not the tests, then
    the tests wouldn’t compile (the tests would need to import
    the "pretend" classes explicitly in this instance)

  3. James Says:

    What’s the code coverage % of clover’s unit tests? :)

  4. Noel Grandin Says:

    You don’t have to just through all those hoops.
    Simply create your own classloader class for loading the covered classes that "defines" the classes it loads itself.
    This works because the VM identifies a class by using the <ClassLoaderObjectId, ClassName> pair.
    So your coverage analyzer and any classes it analyzes will remain disjoint.
    (It’s a little tricky writing your own classloader to do this - took me about a day.)

  5. Matt Quail Says:

    Noel, the problem is, that the very class doing the instrumenting is the one we want to instrument… You can get two different classloaders to load the same class twice, but you can’t get the same classloader to load the one class two "different" ways…

Leave a Reply

Click here to leave a reply