Archive for August, 2006

before/after TestCase with JUnit 3.x

Thursday, August 31st, 2006

With Junit 4.x or TestNG, one can define a before/after class callback which will be called before/after the tests within the test class execute. For those of us stuck with JUnit 3.x I have written a simple extension to JUnit TestCase that allows for it.

It is a very simple implementation, counting the number of tests within the test case, and using the information in order to call the beforeTestCase and afterTestCase callbacks. Note, that if running just a single test within the TestCase (as often done with an IDE), the afterTestCase will not be called (which is often ok, since the JVM will shut down). Here is the code:

/**
 * A simple extension to Junit <code>TestCase</code> allowing for
 * {@link #beforeTestCase()} and {@link #afterTestCase()} callbacks.
 * <p/>
 * Note, the callbacks will only work if running the whole test case
 * and not just one test.
 *
 * @author kimchy
 */
public class ExtendedTestCase extends TestCase {

    private static int testCount = 0;

    private static int totalTestCount = -1;

    private static boolean disableAfterTestCase = false;

    protected ExtendedTestCase() {
        super();
    }

    protected ExtendedTestCase(String name) {
        super(name);
    }

    public void runBare() throws Throwable {
        Throwable exception = null;
        if (totalTestCount == -1) {
            totalTestCount = countTotalTests();
        }
        if (testCount == 0) {
            beforeTestCase();
        }
        testCount++;
        try {
            super.runBare();
        } catch (Throwable running) {
            exception = running;
        }
        if (testCount == totalTestCount) {
            totalTestCount = -1;
            testCount = 0;
            if (!disableAfterTestCase) {
                try {
                    afterTestCase();
                } catch (Exception afterTestCase) {
                    if (exception == null) exception = afterTestCase;
                }
            } else {
                disableAfterTestCase = false;
            }
        }
        if (exception != null) throw exception;
    }

    protected static void disableAfterTestCase() {
        disableAfterTestCase = true;
    }

    /**
     * Called before any tests within this test case.
     *
     * @throws Exception
     */
    protected void beforeTestCase() throws Exception {

    }

    /**
     * Called after all the tests within the test case
     * have executed.
     *
     * @throws Exception
     */
    protected void afterTestCase() throws Exception {

    }

    private int countTotalTests() {
        int count = 0;
        Class superClass = getClass();
        Vector<String> names = new Vector<String>();
        while (Test.class.isAssignableFrom(superClass)) {
            Method[] methods = superClass.getDeclaredMethods();
            for (Method method : methods) {
                String name = method.getName();
                if (names.contains(name))
                    continue;
                names.addElement(name);
                if (isTestMethod(method)) {
                    count++;
                }
            }
            superClass = superClass.getSuperclass();
        }
        return count;
    }

    private boolean isTestMethod(Method m) {
        String name = m.getName();
        Class[] parameters = m.getParameterTypes();
        Class returnType = m.getReturnType();
        return parameters.length == 0 && name.startsWith(“test”) && returnType.equals(Void.TYPE);
    }

}

Compass 1.1 M1 Released

Friday, August 25th, 2006

OpenSymphony and the Compass team are pleased to announce the release of version 1.1 M1. This is the first milestone release of version 1.1, major features include:

  • Sub Index Hashing: Allows to partition mapped searchable content into different sub indexes. Previously, you could only map alias level mapping to a sub index (resource/osem/xsem), and different mappings could be mapped to the same sub index. Now, partitioning on the alias level mapping is possible, i.e. mapping different instances of the same class into different sub indexes (in OSEM). Here is more information about it.
  • Direct Lucene support: Direct access to Lucene IndexReader and Seracher is supported.
  • Lucene Directory Wrapper: Support for custom Directory wrappers and wrappers providers (think of them as Directory aspects), including two ram caches for single instance Compass installations.
  • Better Documentation: Work has been started on upgrading the reference documentation. The first chapters have already been revised, with the rest of the chapters coming in the following milestone releases. Any feedback/corrections is more than welcomed.

Isn't sw development grand?

Monday, August 14th, 2006

It starts with a funny story. When I was in high school, I basically majored in both electricity and software. When I wanted to go to university, what I basically did was flip a coin between the two, and it fell on software. When I got to one of the best universities in the world in both software and electricity majors, I was in shock. I was never the type of teenager that programmed on Atari or whatever, I spent most my time playing basketball and football. I joined the uni and found myself facing people who basically were born with a keyboard on their hands. I was there, typing single 3 seconds timed strokes on the keyboard, where most of my soon to be friends were typing their arse off burning the hell out of the computer. In this I was facing an interesting dilemma, have I chosen the right course? Can I ever match this craziness of knowledge and love for computers?

As it turns out, I did (to some extent). I look back, and love the decision I made. Staying in software development is one of the smartness decision I made. Especially now, and here I get to the point I am trying to make. I have many friends, most of them are as smart as normal people should not be. A lot of them went and studied electronics or bio-informatics. Whenever I speak to them, they are flourishing with this splendid ideas (that I can hardly grasp), and are up to and want to take/change over the world.

And here comes the interesting point, when I talk to this people, my friends, for them to implement and go forth and fulfill their ground breaking ideas, they stumble. Trying to create a new bio-machinery, for example, requires a lot of up front investments. Where someone with a good software related idea can simply sit down and hack his arse off for several weeks, and come up with youtube, digg, google, or anything similar, people in other fields can not take this course. This is what I like about software, it allows for the purist expression of art. Artists simply sit down and work it out, no need for investors, angels or VCs. You sit down and simply paint (or anything else). Same thing happens with software today (mostly different then what happened in the bubble). People, smart creative amazing people, sit down and write software. They are able to express their ideas with minimal investments, and have the Angels/VCs knock on their door. Isn’t software development grand?.

Hibernate Vs. Spring - Hibernate Template

Thursday, August 10th, 2006

Here we GO again. On one side we have Hibernate/Spring yelling “I pity the fool”, and on the other side, we have Spring/Hibernate shouting “Adriaaaaan” (I will leave you to guess which one is which). Again, talking about the famous HibernateTemplate.

First, let me say that now, I hardly see the point of using HibernateTemplate (or JpaTemplate or that matter). I agree with the above hibernate blog statement that it should generally not be used. Here is a really nice tutorial on how to use Jpa in Spring without JpaTemplate, which also applies to direct Hibernate usage (replace Jpa with Hibernate). The problem that I have is the other subtle statement made: HibernateTemplate=Very stupid thing to use=I can’t believe Spring did something like that!.

In the beginning…

In the beginning, there was Hibernate 2.x. Hibernate 2.x used checked exceptions, did not come with advance Jdbc exception translation, and recommended on using its own transaction abstraction. Most of it is perfectly ok, and here is how Hibernate recommended coding Hibernate Session aware code:

Session sess = factory.openSession();
Transaction tx;
try {
    tx = sess.beginTransaction();
    //do some work
    ...
    tx.commit();
}
catch (Exception e) {
    if (tx!=null) tx.rollback();
    throw e;
}
finally {
    sess.close();
}

Then Spring came along, and backed the template design pattern in order to handle code of such nature. Now, nobody says anything about the Spring Jdbc module, and all agree that it really simplifies your code when working with pure Jdbc code in terms of resource management. The same applied for Hibernate 2.x. Usage of un-checked exceptions, externalization of your resource management code, and proper exception handling were a big win when using Spring and Hibernate 2.

Moreover, Spring came with a really nice class, called SessionFactoryUtils. Basically, using it with Spring transaction abstraction, allowed you to write code that looked like this:

Session sess = SessionFactoryUtils.getSession(getSessionFactory(), false);
//do some work, without worrying about transactions
...

If you did not mind the checked exceptions in Hibernate 2.x (which would eventually obscure your code), you could have used Hibernate without HibernateTemplate back then (it also integrated with Spring transaciton management, so no need for that also).

And then there was … Hibernate 3

Hibernate 3 came with several major changes: the move from checked to un-check exceptions, and better Jdbc exception translation (just focusing on the features relevant for this discussion). Hibernate 3.0.1 moved forward, and allowed for what they call Current (Contextual) Sessions, and Hibernate 3.1 moved even further with Pluggable Session management. This features basically boiled down your typical Hibernate code to (that is cross transaction management strategies):

Session s = HibernateUtil.getSessionFactory().getCurrentSession();
s.beginTransaction();

s.save(item); // or
HibernateUtil.getSessionFactory().getCurrentSession().save(item);

s.getTransaction().commit();

ThreadLocalSessionContext.unbind().close(); // Only needed for non-JTA

Spring on the other hand, first needed to support the new Hibernate 3 (with its package name change). There was already plenty of code out there that used Spring Hibernate 2 support, and the goal for the Hibernate 3 support was to make it as easy and backward compatible as possible. This meant that existing code that used HibernateTemplate should still compile and run (with only a package name change). Note also that proper session handling still took some time to happen, and is getting there in Hibernate 3.2.

But still, with the above example we still have code that should not really be there: the handling of transactions, and session context for non JTA code. When using Spring, the above code boils down to:

Session s = getSessionFactory().getCurrentSession();
s.save(item);

Where SessionFactory is one that is created using Spring LocalSessionFactoryBean. Spring would go and proxy Hibernate SessionFactory, allowing the getCurrentSession method to integrate with its transaction and Hibernate session management (internally uses the same SessionFactoryUtils). The same code naturally could be used without Spring when using JTA and CMT, but it will not be cross transaction management strategies.

In the end …

In the end, Spring simplifies the usage of Hibernate. Especially in Hibernate 2.x, and even in Hibernate 3.x. I agree that most of the time, you would not go and change your ORM framework, but this isn’t really the case here. I am sure that Spring support caused Hibernate to simplify the session/resource management, and I am thankful for that. Spring did much more than just that, why do you think we have JBoss Microcontainer?

It is perfectly ok to learn from others, and apply best practices in your own product. Hell, this is what I expect from any company to do. If something works, copy it and enhance it. If I am using your product, I do not want to look over the fence at my neighbor’s grass with envy. The fact that Hibernate/JBoss did just that is great, but don’t try and put a spin on it. Peace.

Mock Shmock

Tuesday, August 8th, 2006

There have been several posts in past week regarding testing, basically trying to explain, that as with anything in software development, things should be taken and applied cautiously. One of the most horrible things that can be done to a software project is using mocks in the wrong way. Let me try and explain why:

Do we really need it?

First, lets start with why do we want to use mocks. On any given project, if someone tells me that they want to test a service implementation (assuming that it performs some dao calls, and some business logic) and mocking out the dao, I would ask them several times if it is really needed. At the end of the day, the most important part of the service layer is to expose a service API, and we would want to test this service API without knowing what is going on within it. It means, that our integration tests, and what I mean by integration here is an environment that works with other immediate external dependencies, like database or other frameworks/libraries, will have to be written in order to prove that our service layer is functional. You can not and should not rely only on your mock tests for it. Now, if we already have the integration tests, which have 100% coverage of all the different execution paths of the service, why would we want to complicate our code with mock tests?

Many of you would then say that integration tests are slow, and mock tests are fast. But I say that if you are running your integration tests against an in memory HSQL instances, and rollback each transaction, it is fast enough.

Another issue that people raise is the fact that if the test fails, we won’t know immediately what went wrong. It might be our test data, transaction handling, or any other non business related aspect of the services tests. What people miss is that most of the time, this is not the case, and the problem is pretty evident. And let me remind you that you still need to run your integration tests, so you would need to solve this problem anyhow.

Test Code is part of your source code

Tests, let it be unit/integration/orwhatchamacolo tests, are part of your source code. When you refactor your main code base, you might need to refactor your test code base as well. Mock tests for the most part are intrusive in nature, they know things about how certain services are executed, how they are called, and the order of their internal execution plan. This means that when you refactor your code, you will need to spend time refactoring your mock tests as well, many times without the IDE help.

From my experience, refactoring mock tests is a pain. Many times you extend the functionality of your service, without changing its API contract, and suddenly mock tests start dropping like flies. This is very noticeble when testing services.

The Danger Of Mocks

Like most things in software development, certain tools / methodologies can be very dangerous in the hands of people who abuse them. Writing proper mock testing is not simple, as well as the decision what to mock test and what not. On several projects that I have worked on, mocks were used as the golden hammer of testing. The projects had so many mock tests, many of them with such an obscure execution and coding, that trying to change existing functionality required changing so many tests. Suddenly a 1 hour feature became a full day work.

The strange thing was that the developers on the project were all above average developers, which for me means that doing proper mock testing, without it being a hassle later on in the porject life is not a simple job, and requires a lot of decipline.

This brings me back to my first point, we still had to write integration tests (and run them before any commit). This integration tests retested most of the mock tests, and we ended up with test duplication, which should be treated as bad as code duplication.

Last Words

I am not saying that mock tests should not be used. I am simply saying that we need to be vigilant in applying it within our code base. There are places where it makes perfect sense to write mocks, and they should be used in such cases. Also, many times, simple mock implementation of an interface (sometimes called stub) is simpler then using an existing mock library, and requires much less understanding or the knowledge of yet another library we use in our project.

Compass on The Java Posse

Friday, August 4th, 2006

Compass 1.0 release just got mentioned in The Java Posse, here is what is written on the site: “Compass 1.0 - born from the Open Symphony java workflow project - has been released”. Now, I am pretty sure that I am not mistaken, but I don’t think Compass was born out of OSWorkflow (which I think is the one they meant to) :). I wonder where they got that info from…, sure as hell not from here ;)