Archive for the ‘Testing’ Category

JUnit V TestNG: Managing external dependencies

Wednesday, August 30th, 2006

We have many components in our product that rely on external packages being available before tests will pass. For example, our make integration requires that make is installed, and our cvs integration tests require the cvs test server to be reachable.

The problem is that some of these resources will not always available on the box running the tests. This is often the case when we are running a build on a new box / environment for the first time. What would be very nice is if the test framework could warn me if a resource is not available, and only run the tests that have a chance of succeeding, ie, those where the required resources were available.

JUnit

Since we use JUnit for testing, I had a look to see what I could do to solve this issue.

The simplest solution is to Assert.fail during the setup/before method if the resource is not available:

@Before public void checkResource()
{
  if (isResourceNotAvailable())
  {
    Assert.fail(“resource not available.”);
  }
}

This results in a:

java.lang.AssertionError: resource not available.
        at org.junit.Assert.fail(Assert.java:69)
        at junit4.DependencyTest.checkResource(
        at sun.reflect.NativeMethodAccessorImpl.i
        at sun.reflect.NativeMethodAccessorImpl.i
        at sun.reflect.DelegatingMethodAccessorI
        at org.junit.internal.runners.BeforeAndAfte
        at org.junit.internal.runners.BeforeAndAfte
        at org.junit.internal.runners.BeforeAndAfte
        at org.junit.internal.runners.TestMethodRu
        at org.junit.internal.runners.TestMethodRu
        at org.junit.internal.runners.TestClassMeth
        at org.junit.internal.runners.TestClassMeth
        at org.junit.internal.runners.TestClassRunn
        at org.junit.internal.runners.BeforeAndAfte
        at org.junit.internal.runners.TestClassRunn
        at junit.framework.JUnit4TestAdapter.run(

for each test that requires the unavailable resource. This is certainly effective, but a little crude, resulting in a lot of meaningless strack traces when all I need to know is that X is not available.

An alternative, in JUnit3 at least, would be to implement a custom TestDecorator that would only execute the tests it wraps if the required resources are available.

pulbic class CheckResourceDecorator extends TestDecorator
{
  public CheckResourceDecorator(ResourceAwareTest test)
  {
    super(test);
  }

  public void run(final TestResult result) {
    Protectable p= new Protectable() {
      public void protect() throws Exception {
        if (isResourceAvailable())
        {
          basicRun(result);
        }
        else
        {
          System.err.println(“resource not available.”);
        }
      }
    };
    result.runProtected(this, p);
  }

  private boolean isResourceAvailable()
  {
    return ((ResourceAwareTest)getTest()).isResourceAvailable();
  }
}

public interface ResourceAwareTest extends Test
{
  public boolean isResourceAvailable();
}

This has the advantage of avoiding the stack traces, and allows us to control the number of error messages printed. This is certainly not as noisy as the first approach, but now we need to wrap all of our tests in this decorator, and does not seem to work well with the JUnit 4 suites.

TestNG

I have heard some good things about TestNG lately, so how does it handle this problem?

TestNG supports the concept of test dependencies. That is, if testB depends on testA, then testB will not run until testA has run successfully.

So, what we can do is define a method to check for a resource, and make tests that require that resource dependent on that method.

@Test public void checkResourceX()
{
  // if resource x is not available, then fail.
  Assert.fail(“resource X not found.”);
}

@Test(dependsOnMethods = {“checkResourceX”})
public void testThatRequiresResourceX()
{
    // run the tests.
}

The result is that if the resource is not available, you get a single failure with details “resource X not found”, with tests that depend on that resource will be marked as skipped. That is pretty clean outcome. We get no duplicate failures and a short error message:

java.lang.AssertionError: resource X not found.
        at org.testng.Assert.fail(Assert.java:76)
        at testng.dependency.DependencyTest

Short and definately Sweet.

Conclusion

Given these results, I certainly prefer the TestNG solution. The output is clear and the association of dependencies to tests is defined with each test case and on a per test basis, not on the per class basis as with JUnit. Now if only I was using TestNG :) . Maybe it is time to run the JUnitToTestNGConverter?

I am curious to know if other people run into this issue? And if so, how do you solve it? Maybe you do one of the above, or have written custom annotations or extended JUnit. Please let me know, I would love to hear about it.

Article: The Road To Build Enlightenment

Wednesday, August 23rd, 2006

Each day, every developer on a software team interacts with the build system several times. Despite this, many teams underplay the importance of an effective build system. Is your build system working for you, or do you merely tolerate its existence? In this article, we will journey through build system requirements starting from the most basic through to those that make the whole development process more efficient.

Read the The Road To Build Enlightenment at zutubi.com.

Does Testing Slow You Down?

Thursday, June 8th, 2006

Earlier today I read Cedric Beust’s post Agile People Still Don’t Get It. In that post Cedric makes some fair criticisms of misguided agile evangelism. I find it particulalry ironic that the closing sentence is:

So here is my advice to Agilists: get real now, or you will become irrelevant soon.

Pragmatism should be a cornerstone argument for agile development, so those evangelists that don’t emphasise it surely are doing more harm than good1.

Having said all that, there is an interesting undertone in some of Cedric’s comments that got me thinking. In his defense of pragmatism, Cedric makes repeated assertions that sometimes we need to cut corners to make a real-world deadline. One corner to be cut is testing:

But the truth is: at times, I don’t do TDD because implementing a feature quickly is more important than a fuzzy feeling.

This is what really got me thinking. Note that we are talking short-term here: in the long term, I think most would agree that cutting corners will catch up with us eventually. But why do we assume that cutting this corner will save time in the short term? I think the assumption is based purely on a shallow evaluation: writing less code this second means I can hit the looming deadline more easliy. This seems valid enough: writing the extra code to perform the testing takes non-zero time after all. But the analysis is missing something: can we really implement a feature without testing it? We can try, but how will we know if it works at all? A broken feature is worse than no feature at all, so there is no way to invoke the “customer value” argument here.

I think most people agree that some level of testing is required: the risk of zero testing is just too great. A temptation, then, is to test the feature by hand, because that will be quicker than writing code to test it. Now the assumption is getting even shakier. Maybe a manual test is quicker as a once-off, but what about when you find a problem? Now you need to fix the code, then manually test again. You will be wishing you had just written test code in the first place, so you could repeat the test with very little extra effort. So, counter-intuitively, it may be quicker to code the feature and tests rather than just the feature. Not in all cases, for sure2, but probably more frequently than we realise.

In fairness to Cedric, I have taken this off on a tangent of my own. His post just got me thinking about a natural assumption that we tend to make which may actually be false. I agree with the assertion that sometimes a pragmatist has to make compromises to meet a short term goal, I just wonder about the short term effects of this particular compromise.


1 I suppose this is what happens when people become true believers in a methodology: they start to drift farther and farther from reality.

2 For example, when the feature is very hard to test in an automated fashion. Usually this can be remedied in the long term, when you can afford the extra time to refactor for testability.