Jan 14

How to be agile when all about you are not – part 5


In part 4 of this series
, I explained how continuous integration is used to automate the build process. In this article, I shall go on to explain how to further apply the DRY principle with fully automatic standardised build processes that generate code for you.

One of the biggest problems with build scripts is that they are tailored to a specific system and cannot be reused. Furthermore, every developer (and IDE) has their own ideas about how a project should be laid out; where compiled code should be placed and where the dependencies are stored. In some cases there are very good reasons why code is where it is, but more often than not it is because of some kind of workaround to overcome a limitation of the build process.

For a long time, Ant was the king of the Java build process. It is present in just about every mainstream IDE that supports Java and is a solid and reliable workhorse in the development process. However, Ant has many limitations (dependency management and script standardisation being two of the main ones) which is why the developers of Ant moved on to create Maven.

The idea behind Maven is to provide a unified build process that can be applied to just about any project of any size in an intuitive manner. It favours certain conventions that if followed makes your project immediately accessible to anyone else who knows Maven. Learning curves drop considerably for new developers joining the team since they will already know where to find code and how the build process works. Maven is extensible via plugins so that esoteric build requirements can quickly be catered for, and a large number of standard plugins are available for free. These include plugins for creating EAR files, automatically generating code, linking back to Ant scripts and just about every other purpose you could think of.

So how is this in line with the DRY principle? By providing a single point of reference for all project build information that is defined in a consistent format: XML. When I say all project build information, I mean it. Apart from the obvious “project name” and “version” there is a plethora of other information: who the developers are along with contact information; how to run automated tests and where to publish the results; how to generate the javadocs and where to publish them; how to manage versioned releases; how to generate the overall website associated with the project and where to publish it; and, most importantly of all, how to manage the project dependencies.

And in that closing entry lies the distillation of the DRY principle: a single point of reference for all the dependencies of the system, along with their versions so that they do not need to be stored within the project any longer. For many developers this comes as a great relief because there is no need to work out which version of, say, cglib.jar is copmatible with both the Spring 2.5.5 and Hibernate 3.3 frameworks. Instead, all Maven needs to know is what version of Spring you’d like, and which version of Hibernate and it works out the rest.

Maven also provides a very simple but powerful mechanism for avoiding repetition with the project file itself. For example, if the project has an overall dependency on Spring this is actually implemented as a small collection of dependency entries containing the precise modules of Spring that are needed (say core, transactions, web and MVC). If done without thought then there will be 4 places where the version, say 2.5.5, is referenced. However, the designers of Maven have provided a properties mechanism so that this repetition is confined to the name of a property that contains the appropriate version. Thus, to change from 2.5.5 to 2.5.6 all that is required is a simple change in the value of the property and all places where that property is referenced will be automatically updated. In a large build with many modules this saves an enormous amount of work and creates a very orderly build system.

At this point you have a very flexible and easy to maintain build system and a comprehensive set of automated tests that is providing protection against brittle code. So what next? Plenty. You have an agile build process, but you probably don’t have an Agile approach to design and implementation. For that you need to follow the trail “How to be an agile project manager” (coming soon).

Share
Tagged with:
Jan 06

I’m a big fan of automated testing, in fact automated everything since I quickly lose interest in repetitive tasks. As a result of this I’m drawn to build systems like Maven which provide a lot of good conventions and automation right out of the box.

There are a million articles out there about Maven so I’m not going to repeat what they say here, but I would like to comment about a particularly tricky problem that I encountered a little while ago which ended up having a very neat solution.

Hudson duplicates the results of multiple executions of a test suite through Maven so that a failure in, say, the first run is overwritten by a success in the second. Hudson signals the failure in the build report and the test report contains multiple entries with the same class and method name, one marked as a failure the other as a success and no reliable stack trace highlighting which of the executions was responsible for the failure. How can Hudson be made to provide separate test reports for each test suite execution?
Firstly, it should be noted that Hudson runs Maven in a special way which allows it to trigger operations when plugins complete. In the case of automated testing Hudson is able to slip in between plugin executions and extract the test results before another plugin is able to execute. This rules out a plugin based solution (although I did have some fun writing one only for it to fail to solve the problem).

The way to solve the problem is to change the JUnit4ClassRunner that is being used by JUnit to one of your own making which is able to modify the returned name of the test method that has been executed. This allows a test method to have, for example, a different suffix depending on an environment variable that can be passed in by Maven. This feature is easy to implement if you are using JUnit4 (which is backwards compatible with JUnit3 so there’s no excuse not to upgrade).

In Maven the surefire plugin provides access to JUnit tests and thanks to the <executions> configuration element the plugin can be repeated with different settings. For example,

<executions>
  <execution>
    <id>1_FF3</id>
    <phase>integration-test</phase>
    <goals>
      <goal>test</goal>
    </goals>
    <configuration>
      <environmentVariables>
        <browser>ff3</browser>
      </environmentVariables>
    </configuration>
  </execution>
  <execution>
    <id>2_IE6</id>
    <phase>integration-test</phase>
    <goals>
      <goal>test</goal>
    </goals>
    <configuration>
      <environmentVariables>
        <browser>ie6/browser>
      </environmentVariables>
    </configuration>
  </execution>
</executions>

The above, if placed within a surefire plugin declaration, will run the test suite twice, once passing in “ff3″ as an environment variable (“browser”) and the second “ie6″.

Typically, most JUnit test cases inherit from some common base class that provides common methods, so I’ll assume that you’ve got something like AbstractWebTestCase below:

@RunWith(JUnit4ClassRunner.class)
public abstract class AbstractWebTestCase {}

The next step is to write your own replacement for JUnit4ClassRunner so that the Description object is constructed with slightly altered values. This is actually pretty trivial since you only need to override a single method:

public class SuffixEnabledJUnit4ClassRunner extends JUnit4ClassRunner {
    public SuffixEnabledJUnit4ClassRunner(Class clazz) throws InitializationError {
        super(clazz);
    }
    @Override
    protected Description methodDescription(Method method) {
        String suffix = System.getenv("browser");
        return Description.createTestDescription(
          getTestClass().getJavaClass(),
          testName(method)+suffix,
          testAnnotations(method));
    }  
}

Using the above example, you should be able to construct your own JUnit4ClassRunner which will modify your method name descriptions in the manner of your choosing. Hudson will merrily use whatever name is given out by your ClassRunner so feel free to experiment.

Share
Tagged with:

You should follow me on TwitterYou should follow me on Twiiter here.

preload preload preload