Home | About Us | Stelligent  

TestEarly Weblog

July 2007


Continuous Integration and /Owens and Vidcast25 Jul 2007 01:57 pm

3240 revisions, 3124 pages written, 336 pages published
911 days, 100 weekends, 30 unpaid days off work
651 Starbucks mochas…

Check out the book trailer promoting the release of Continuous Integration: Improving Software Quality and Reducing Risk and see if you’re not enticed to order a few copies.


Developer Testing and /Glover23 Jul 2007 09:42 am

JUnit 4 has been on the streets for almost 2 years and it appears that it is readily being embraced based upon the data thus far gathered from an informal poll. While it’s no surprise that a majority of respondents (40%) are still using the bellwether of developer testing (JUnit 3.8.x), it is rather impressive that the second most popular framework is JUnit 4 at 33%.

Interesting, too, is that TestNG is not too far from JUnit 4 in terms of votes. To be even on the map in the face of such a giant is an impressive achievement.

The question still stands though– if you are a Java developer, what test framework are you using?

For more information on these frameworks, check out:

Developer Testing and /Glover and Business Perspectives16 Jul 2007 08:33 pm

Behavior driven development (BDD) is an evolutionary result of test driven development (TDD) in the sense that rather than thinking in terms of tests (which have the tendency to make you think after the fact) you can more easily think in terms of a specification. By thinking about an application’s specification or behavior, it becomes easier to validate things early– in fact, when thinking in terms of a specification, it becomes quite easy to write things upfront.

To take a simple example, imagine a customer has asked that you create some sort of validation service for the ordering flow of their online business. Specifically, customers keep mistyping zip codes, which unfortunately delays the shipping process (which happens to cause customers to complain and use up valuable customer service representatives’ time). Consequently, the customer believes this small improvement will save the company money. It is a simple job that won’t take long (but the consequences for messing it up are rather large).

Wanting to be agile, I want to get something quickly in front of the customer– but rather than jumping into the coding process, I’ll begin to specify behavior à la BDD (in this case, JBehave). At a minimum, it is decided that I’ll need an interface, which provides a simple contract:

public interface Validatable {
  boolean validate(String value);
}

For a given String instance, an implementing class will return true or false based upon the validation requirements.

Next, I can specify a quick and dirty specification class (which I can show to my customer, if they speak code) that outlines a few, albeit sunny-day scenario, methods:

public class ZipCodeValidationBehavior extends UsingMiniMock{
 public void shouldAcceptInvalidZipCode(){}
 public void shouldDenyInvalidZipCode(){}
}

Note how this class doesn’t use the term ‘test’ — rather, the phrase ’should’ is utilized, because it turns out to be a bit more natural. Should equates to behavior, which is what I’m focused on at the moment.

As I haven’t actually coded a the business class yet, I’ll use JBehave’s mocking library to roughly specify my intended behavior. For example, given what I believe is a good zip code, the validation service should return true and consequently, given a bad zip code, the service should reject it.

To mock things easily, I create a simple helper method that returns a mock instance of the Validatable interface:

private Validatable getValidatable(boolean returnValue) {
 Mock validator = this.mock(Validatable.class);

 validator.expects("validate").with(new Matcher() {
  public boolean matches(Object arg) {
   return arg instanceof String;
  };
 }).atLeastOnce().will(returnValue(returnValue));

 return (Validatable) validator;
}

This method creates a Mock instance and specifies that the validate method will return what ever value was requested at instantiation time (either true or false, in this case). In addition, the method specifies that the mock’s validate method may be called with a String as an argument (there is probably an easier way to specify this without having to create a new Matcher type, but I’ve yet to figure that out) and may be called more than once.

Keep in mind, the point of this mocking exercise is to help me flesh out my desired behavior– once things are kosher, I can presumably remove the mock and use the real object (which will immediately be verified with the behavior methods I’m about to implement).

I can now implement the shouldAcceptInvalidZipCode method like so:

public void shouldAcceptInvalidZipCode() {
 List<String> goodzips = Arrays.asList("22101", "22101-5100");
 Validatable validator = this.getValidatable(true);
 for (String zip : goodzips) {
  boolean value = validator.validate(zip);
  ensureThat(value, eq(true));
 }
}

As you can see, a List of what I believe are valid zip codes is looped over and the mock is utilized as expected– true is returned every time.

I can also implement the shouldDenyInvalidZipCode method as follows:

public void shouldDenyInvalidZipCode() {
 List<String> badzips = Arrays.asList("221o1", "22101-100");
 Validatable validator = this.getValidatable(false);
 for (String zip : badzips) {
  boolean value = validator.validate(zip);
  ensureThat(value, eq(false));
 }
}

Thus far, I haven’t written a line of real business code, but I’ve now established the behavior I intend to write. I can run this behavior via JBehave’s runner and see the veritable green bar:

..
Time: 0.046s
Total: 2. Success!

What’s more, I can even go over this behavior with my customer or even with the QA department, business analysts, etc– it doesn’t really matter and the intent is the same– does this behavior work according to your specification (in this case, your specification of a valid or invalid zip code?).

Assuming everyone in onboard, I can move forward, or if things are not correct according to a stake holder, I can make fixes and I haven’t really lost much– a few cycles in JBehave, but I haven’t yet written any real code.

If things are good to go forward, I can implement the Validatable interface with a real class that hopefully validates zip codes:

public class ZipCodeValidator implements Validatable{
 private String zipRegEx = "^\d{5}([\-]\d{4})?$";
 private Pattern pattern; 

 public ZipCodeValidator() throws Exception {
  this.pattern = Pattern.compile(this.zipRegEx);
 }  

 public boolean validate(String value) {
  return this.pattern.matcher(value).matches();
 }
}

With my class implemented, I can now refactor my behavior class and plug in the real deal. Once I’ve done that, I can rerun the behavior methods to verify things work as intended. First, I’ll refactor the getValidatable method like so:

private Validatable getValidatable(){
 return new ZipCodeValidator();
}

Then, I need to fix each behavior method to invoke the proper getValidatable method; once that’s finished, I need to rerun the behavior class and voilà, things work as planned!

..
Time: 0.024s
Total: 2. Success!

As you hopefully can see through this example, BDD is an efficient way to drive the development of features in a rapid manner by communicating behavior rather than tests, which as I’ve found is a rather simple shift in thinking that opens the door to a wider audience of acceptance. Don’t get me wrong– I absolutely love writing tests in JUnit and TestNG, but I find these frameworks are a bit hard to get people to adopt upfront. No doubt, these frameworks offer a huge benefit when it comes to larger scale testing, such as component and system testing where large swaths of code are being verified.

/Glover and Vidcast15 Jul 2007 07:41 pm

If you were wondering who that stranger was that accosted you and handed out an extremely handy and undoubtedly cool ruler, you can learn more about him (and his company) by watching this interview that took place in between random ruler handouts. If you look closely, you can even see people seeking out the rulers in the background.

Don’t forget to pick up a few copies of the newly released “Continuous Integration: Improving Software Quality and Reducing Risk” book too!

Build Management and Code Metrics and /Owens and Podcast12 Jul 2007 02:46 pm

For his latest Automation for the people installment, “Asserting architectural soundness”, Stelligent CTO, Paul Duvall, demonstrates how using tests such as JUnit, JDepend, and Ant can play a role in enforcing architectural reliability.

Asserting architectural soundness describes a technique to build checks into your build scripts to proactively detect violations while coding. Locating potential deviations as soon as they’re introduced, instead of waiting to flag problems after the fact, ultimately leads to better quality software delivered faster.

In addition, Scott Laningham, host/editor of IBM developerWorks podcasts, interviewed Paul about the software development need that he addressed in the article. Paul kicked off the interview by indicating that,

Over time software architectures tend to become brittle. The architecture that you think you have versus the architecture that you actually have, as its manifested in the code, is often different.

Whether you read the article or listen to the podcast (hopefully both!), you’ll undoubtedly carry away the need to take charge of your architecture by using a proactive build process.

Build Management and Continuous Integration and /Glover08 Jul 2007 12:25 pm

Gant is a build system that sits on top of Ant, which uses Groovy as the platform language, rather than XML; thus, build files are much more flexible when it comes to logic (such as conditionals and more importantly, custom behavior).

Gant’s syntax is highly intuitive as it follows a natural structure for defining behavior (that is eventually embodied by a tried and true Ant task). The basic structure can be defined as

target (target-name:target-description) {
  //do stuff
}

What’s more, you can define methods within Gant scripts, which can be referenced from various tasks. For instance, given that many builds have multiple compilations (such as compiling source code and compiling tests), you can easily create a generic compilation method and then reference it from different target definitions (such as compile-src and compile-test). This generic behavior can be defined as a closure like so:

genericjavac = { source, destination ->
 Ant.javac(srcdir:source, destdir:destination){
  classpath(refid:"build.classpath")
 }
}

As you can see, this closure accepts two parameters (the source directory and the destination of the resulting class files) and accordingly invokes Ant’s javac task. You can then reference this closure from within targets like so:

task(compile-tests:"compile test classes only") {
 genericjavac(testsdir, testclassdir)
}

Hudson is CI server, written with a lot of the lessons learned from previously written CI servers, that aims to be extremely easy to set up. Hudson supports running a number of different types of builds such Ant and Maven; moreover, Hudson supports executing outside shells and batch files.

Running a non-Ant or Maven build requires that you specify the Execute shell option (that is, if you are on a Unix-ish machine) in the Build section of a project’s configuration. What’s key, though, is that the command is invoked from an outside directory as opposed to the project’s root directory (where builds are usually run from). This normally isn’t an issue, however, unless you’d like to run a Gant build.

The issue is that Gant builds don’t (at this point it seems) handle base directory behavior by default like normal Ant builds do. Therefore, if your Gant build assumes some relative paths (such as those paths used in configuring Ivy) and the Gant process is invoked outside of the assumed base directory things will fail, because these relative paths will be from outside the project’s root. Luckily, this issue can be solved easily via Gant’s expressiveness.

The fix involves putting a check in a Gant build that determines where a build is being invoked from. If the build is not within the project’s root directory, a simple check (and corresponding fix) is to see if the project’s root directory is one level down (which is exactly where Hudson executes shell scripts).

Accordingly, you can create a simple check method within a Gant build that attempts to figure out from where the process is being invoked. If it is not within the project, the method attempts to see if the project is one level down and correspondingly sets Ant’s base directory.

def manageBaseDirectory(){
 def runloc = Ant.project.properties.basedir
  if(!runloc.endsWith("/acme") && new File("./acme/").exists()){
   Ant.project.setBasedir("./acme/")
  }//else clause hasn't been thought through yet...
}

This method is invoked from within a default target (which Hudson will invoke based upon the shell command given, such as acme/gant.sh -f ./acme/build.gant) and as written is safe enough to facilitate running normal builds within a project’s root directory.

Now with this small fix, builds can be executed via Hudson (from outside the root project dir) or via developers from within the root directory. There are probably some additional checks that should be added to the method as written, but at this point, it is good enough.

Developer Testing and Continuous Integration and /Owens03 Jul 2007 01:38 pm

Last Thursday evening we had a terrific turnout for our first “war stories” event. With almost 25 attendees, including the co-founder of CruiseControl, the affair went remarkably well.


The majority in attendance were local technical folks with the notable exception of Paul Julius who flew in from South Dakota (he also was the lucky winner of an iPod Nano!).

After mingling over fine wines (provided by Savoy-Lee) and cheese, we dove right into discussing the ins and outs of Continuous Integration and its importance as it ensures the health of software through running a build with every change. Interesting to note, there was no shortage of people eager to talk and share their successes and challenges. One message that resonated throughout the night - “if Continuous Integration is so good, why doesn’t every team use it.”

Additionally, Paul Duvall (CTO, Stelligent) presented a short demo of how to best use CruiseControl in a team environment. Later, Andy Glover (President, Stelligent) presented a similar demo of Hudson (open source CI server).

With a scheduled event end of 7:00 PM the conversation did not cease with the timeline…by 8:30 there were still a few hardcore enthusiasts deeply in the weeds of the CI subject. :)

Many thanks to everyone for coming and stay tuned for details for our next event!

Continuous Integration and Podcast and Vidcast02 Jul 2007 12:29 pm

Here is a vidcast of a short CruiseControl.NET Demo. You can get a look and feel of what a continous integration server can do for you.