Home | About Us | Stelligent  

TestEarly Weblog

March 2008


Developer Testing and Continuous Integration25 Mar 2008 02:57 pm

If you are using IE and trying to configure Matrix-based security, beware. It doesn’t work no matter how many times you click the Add button.

Hudson in IE7

At this point, don’t panic. Rather than changing the config.xml and manually adding all the users and setting their permissions, download Firefox, and you will be easily able to configure the same as shown below:

Hudson in Firefox

Developer Testing and Continuous Integration24 Mar 2008 01:00 pm

Hello!

Andy has graciously invited me to post here at testearly.com, and I thought I would start off with some of my experiences with configuring Hudson. This is a crosspost from my blog, but I suspect it will get a lot more traffic here.

Let’s say you’re using Hudson as your build/Continuous Integration tool. And let’s assume you have some jobs running inside Hudson that you want to keep running, even if the build machine blows up. You probably want to maintain:

  • Hudson itself
  • All the plugins
  • The overall configuration
  • The per-job configuration

Naturally, then, your thoughts should turn to “How do I put the Hudson configuration into source control?” Here’s what you do:

  1. Make sure your builds are configured and working to your satisfaction, in a directory that I will from now on refer to as HUDSON_HOME.
  2. Copy the entire HUDSON_HOME directory tree to a temporary location called “versioned_build”
    1. In the versioned_build directory, you’ll find the jobs directory, and under that, a directory for each job.
    2. Inside each job directory, you’ll find configuration .xml files and other miscellaneous files, and you’ll find two subdirectories:
      • workspace
      • builds
    3. Empty those two subdirectories of all files, but do not delete the subdirectories.
  3. Repeat this “clean out” process for each job.
  4. import the entire “versioned_build” directory tree into source management.

Now, you have your Hudson configuration in source control. You can start it up, and assuming HUDSON_HOME is set right (see below), you should see your dashboard, and your jobs listed, and properly configured. Issues

  • You may have to manually kick off your jobs to “prime the pump”
  • Your build number will not start at 0 unless you do not archive the nextBuildNumber file
  • Your HUDSON_HOME environment variable may be incorrect for your machine (see below)

HUDSON_HOME Portability For ease of checkout and maintenance, I like the following directory setup: $HUDSON_HOME/

  • hudson/
    • hudson.war
  • jobs/
    • Your Hudson Jobs Here
  • plugins/
    • Your Hudson Plugins Here

Using this configuration, you can create a file in $HUDSON_HOME called, say, hudson.sh, which would look a little something like this:


#!/bin/sh
export HUDSON_HOME=.
export CVS_RSH=/usr/bin/ssh
java -jar hudson/hudson.war

Using this structure, and that hudson.sh script (I presume you can do something similar in Windows) gives you the following benefits:

  1. Your entire Hudson system, including the Hudson war file and the launcher script are all maintained as part of the repository.
  2. You don’t have to set HUDSON_HOME whenever you check the system out of source control - it’s already set by default to the current directory. As long as you run hudson.sh in its own directory, you’ll get the correct value for HUDSON_HOME

Learn from my mistakes!

  • Unless you absolutely must, don’t tell Hudson where to find Ant or the JDK. If they’re on your path, Hudson will find them on its own. If you set them for your build machine, chances are that on the checkout machine they won’t be in exactly the same place
Developer Testing and News and Continuous Integration and Agile24 Mar 2008 09:22 am

InformIT has published a Q&A with Stelligent’s CTO, Paul Duvall. Paul shares his thoughts on adopting CI, the future of CI, and of course, his thought provoking blog entry. Check it out!

Developer Testing and Continuous Integration21 Mar 2008 10:42 am

Hudson is an open source CI server that offers quite a few compelling features (in addition to its easy setup and configuration) that come in handy from time to time. For instance, Hudson offers a Groovy plug-in that facilitates executing arbitrary Groovy scripts (or code) as a part of a build.

hudson-groovy

Groovy can be quite useful for simple tasks, which when written in some other form (like an Ant script) requires a lot of plumbing– for example, recently, as a part of a CI project setup, another dependent project’s directories were becoming read-only due to an SCM feature. Consequently, a child project couldn’t write to the filesystem.

This problem was easily solved using Groovy (plus a little Ant)– a triggered build executes a small Groovy script that uses Ant’s chmod task to make target directories read-write enabled. As you can see, the fix requires 2 lines of code (which could, arguably, be reduced to one):

def ant = new AntBuilder()
ant.chmod(dir:"./ci09_i/ui/rep2/reports/", perm:"ugo+rw", includes:"**/*.*")

Hudson’s so Groovy that it’s hard to ignore this CI server as a viable option!

Developer Testing and Agile12 Mar 2008 11:23 am

easySince Selenium was introduced a few years back, it has continued to wow developers with how easily a user acceptance test can be knocked out– simply fire up an instance of a Selenium server in the background and then either write a table test or a RC style test– it’s that easy.

RC style testing is particularly powerful as you have full access to programming languages– for instance, with RC, you can write a functional web test in Java by leveraging a framework like JUnit or TestNG. But what’s often lacking with testing frameworks is a more natural way of expressing behavior– or indeed, scenarios and stories.

For instance, a user acceptance test is really a scenario– a user logs into a website, purchases an item, pays, and logs out. That was a sunny day scenario– there are other scenarios that deal with various other paths– user fails to pay, credit card was invalid, etc. All of these scenarios are logically a story– a story about buying something.

Using a standard scenario language, I can more specifically write a scenario (in a story regarding a website for race registrations) like so:

  • given a user is on the race report page
  • when someone enters a first name and last name in the race report form for someone who has signed up for a race
  • then they should receive a list of all races that person has singed up for

That is a happy day scenario isn’t it? One particular negative path would be:

  • given a user is on the race report page
  • when someone enters a first name and last name in the race report form who hasn’t signed up for any races
  • then they should receive a message indicating the person hasn’t signed up for any races

These scenarios can be easily created using easyb, which is a BDD framework for the Java platform– easyb leverages a domain specific language (or DSL) which supports the following syntax for scenarios:

scenario{
 given "", {}
 when "", {}
 then "", {}
}

This DSL is highly flexible– you can chain phrases together with an and phrase and you can have multiple givens or whens or thens if you’d like. Also too, the scenario phrase isn’t required either.

The DSL makes the assumption that scenarios are in files that are either named YourNameStory.groovy or YourName.story– note that YourName is what ever you’d like.

Using easyb then, I can create a story file, which contains two scenarios– my file will be called RaceReport.story and I’ll start by defining two scenarios:

scenario "a valid person has been entered", {}
scenario "an invalid person has been entered", {}

Given that I plan to leverage Selenium, I’ll have to introduce a few new phrases– for instance, a then one that shuts down Selenium.

I’ll start the RC instance in a given phrase like so:

given "selenium is up and running", {
 selenium = new DefaultSelenium("localhost",
  4444, "*firefox", "http://acme.racing.net/greport")
 selenium.start()
}

Note how I’m connecting to a server instance running on the same machine, which will utilize Firefox.

Next, I can chain two when clauses to simulate a user interacting with the report page.

when "filling out the person form with a first and last name", {
 selenium.open("http://acme.racing.net/greport/personracereport.html")
 selenium.type("fname", "Britney")
 selenium.type("lname", "Smith")
}

and

when "the submit link has been clicked", {
 selenium.click("submit")
}

My then clause then verifies that 4 race instances have been returned for my user– note how I’m able to use a nice Groovy for loop that uses a positional index to grab items from a list and from an XPath expression. Not bad, eh?

then "the report should have a list of races for that person", {
 selenium.waitForPageToLoad("5000")
 values = ["Mclean 1/2 Marathon", "Reston 5K", "Herndon 10K", "Leesburg 10K"]
 for(i in 0..<values.size()){
  selenium.getText("//table//tr[${(i+3)}]/td").shouldBeEqualTo values[i]
 }
}

Lastly, I need to shut down selenium:

and

then "selenium should be shutdown", {
 selenium.stop()
}

The entire first scenario looks like this once you put it all together:

scenario "a valid person has been entered", {

 given "selenium is up and running", {
  selenium = new DefaultSelenium("localhost",
   4444, "*firefox", "http://acme.racing.net/greport")
  selenium.start()
 }

 when "filling out the person form with a first and last name", {
  selenium.open("http://acme.racing.net/greport/personracereport.html")
  selenium.type("fname", "Britney")
  selenium.type("lname", "Smith")
 }

 and

 when "the submit link has been clicked", {
  selenium.click("submit")
 }

 then "the report should have a list of races for that person", {
  selenium.waitForPageToLoad("5000")
  values = ["Mclean 1/2 Marathon", "Reston 5K", "Herndon 10K", "Leesburg 10K"]
  for(i in 0..<values.size()){
   selenium.getText("//table//tr[${(i+3)}]/td").shouldBeEqualTo values[i]
  }
 }

 and

 then "selenium should be shutdown", {
  selenium.stop()
 }

}

That’s pretty easy, don’t you think? Of course, my next step is to implement some additional scenarios, such as negative paths with an non-existing runner, etc.

When I run this via the easyb runner, I can get a story printout that looks something like this:

12 behavior steps executed successfully
 scenario a valid person has been entered
  given selenium is up and running on website
  when filling out the person form with a first and last name
  when the submit link has been clicked
  then the report should have a list of races for that person
  then selenium should be shutdown
 scenario an invalid person has been entered
  given selenium is up and running on website
  when filling out the person form with a first and last name
  when the submit link has been clicked
  then the report should have a list of races for that person
  then selenium should be shutdown

The scenarios are slight variations of one another, hence the report looks quite similar — each step is the same, just the data varies.

Functional web stories are a powerful mechanism to verify the proper behavior of web applications from a user’s standpoint. Combining a framework that supports stories and scenarios with Selenium yields an easy way to deliver software more quickly and collaboratively.

Developer Testing and News and Continuous Integration and Publications07 Mar 2008 11:44 am

On Wednesday evening, I had the pleasure of attending the Jolt Awards ceremony where Continuous Integration: Improving Software Quality and Reducing Risk was a finalist….and WON for best technical book!

Stelligent’s own, Paul Duvall, and co-author, Steve Matyas were on to hand to accept the trophy- which is essentially a giant can of Jolt cola encased in a Lucite block. You have to see it in person- the design is very cool (and it’s heavy!).

Many congratulations to Paul, Andy, and Steve; as well as the contributors, editors, and publishers who brought this book to life! This year’s winners will be featured in the June 2008 issue of Dr. Dobb’s Journal.

Next Page »