Skip to content

John Ferguson Smart's Blog
Syndicate content
Updated: 1 hour 46 min ago

'Real Programmers Don't Need Unit Tests' in London this September

Mon, 08/30/2010 - 06:42

 I will be in London this September giving a talk for Skills Matter on why "Real Programmers Don't Need Unit Tests":

Unit testing is a vital but neglected art. Good unit tests don't just test code: they are executable requirements that tell the story of your application, clarify your design, document your code and help track your progress. They help you find bugs fast, and fix them with confidence. If Real programmers don't need unit tests, they sure make life easier for the rest of us! More details...

This is a fun talk, so come along and enjoy!

There are also still a few places left on the London session of the Java Power Tools Bootcamp (September 13-17) - this is a great workshop covering the finer points of build, release and deployment automation with Maven 2 and 3, advanced Continuous Integration and Deployment with Hudson, automated code quality, and kick-ass test automation, BDD and ATDD with advanced JUnit 4, WebDriver and easyb! So don't miss out - sign up now!

Categories: Blogs

Vote for your favorite build and CI tools!

Thu, 08/26/2010 - 08:24

More exciting than the Australian Elections! The 2010 Wakaleo Build and CI Tools Poll is out! Come vote for your favorite tool(s), and get an idea of the adoption rate of other tools.

 

 

 

 

Categories: Blogs

Hudson and JUnit Kung Fu at JavaOne this year

Tue, 08/24/2010 - 01:21

This year, I'll be giving two talks at JavaOne: one on Hudson and one on JUnit. Here are the rundowns:

S312977 - Getting More from Your CI Server: Taking Hudson to the Next Level

Hudson is an excellent open source, continuous integration server with a rich and rapidly evolving feature set. Targeted to developers, lead developers, and architects interested in implementing CI with Hudson or enhancing their existing CI setup, this session will focus on using Hudson's more advanced features to go from Continuous Integration to Continuous Quality and Continuous Deployment. The session will focus on how Hudson can help with:

  • Enforcing code quality metrics
  • Build promotion strategies
  • Automated release and deployment
  • Web and performance testing
  • Distributed builds and CI in the cloud

 

 

S312958 - JUnit Kung Fu: Getting More Out of Your Unit Tests

JUnit is the de facto standard in Java testing. Yet many advanced JUnit features are little known and poorly understood. This session reviews some lesser-known features of JUnit, along with a few associated libraries, that can make your unit tests more powerful, expressive, and fun. The session is intended for Java developers, lead developers, and architects trying to introduce good testing practices into their teams. Attendees will learn about:

  • The fine art of naming your tests
  • Writing clearer and more expressive tests with Hamcrest and Mockito
  • Data-driven testing in JUnit with parameterized tests and theories
  • Using JUnit rules to extend your test cases and writing your own rules to customize JUnit
  • Using JUnit categories to group your tests
  • Getting faster feedback with parallel testing and continuous testing tools

 

I'm looking forward to catching up as well, so do give a yell if you intent to be at JavaOne this year.

And if you want to learn even more about JUnit, Hudson and lots of other cool tools, be sure to check out the Java Power Tools Bootcamps - scheduled soon for London and Canberra.

 

Categories: Blogs

Managing version numbers in Maven with the Maven Versions plugin

Wed, 08/18/2010 - 12:43

If you have a Maven project of any size, particularly involving many modules or large numbers of dependencies, you have probably come across issues when updating your version numbers. Of course the Maven Release Plugin does a great job for updating version numbers as part of the automated release process, but there are times when it doesn't quite fit the bill, and version numbers are not limited to the main project versions.

The Versions Plugin very useful but not-so-well-known Maven plugin that gives you a number of tools in this direction. You should check out the website for a full list of everything this plugin can do, but here, I just want to cover a few highlights.

The Versions plugin, as the name suggests, helps you manage versions in your Maven projects. Versions of your artifacts, of course, but also versions of your dependencies and of your plugins. Let's take it for a spin.

The first thing you might want to do is to get an idea of the lay of the land, and see what dependencies in your project need updating. In large projects, the dependencies you use often become out-of-date over time, so it's nice to know when new ones are available. You can do this using the versions:display-dependency-updates command, which will list the dependencies you are currently using, and which ones are due for an update:

$ mvn versions:display-dependency-updates
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'versions'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Game of Life business logic module
[INFO]    task-segment: [versions:display-dependency-updates]
[INFO] ------------------------------------------------------------------------
[INFO] [versions:display-dependency-updates {execution: default-cli}]
[INFO] The following dependencies in Dependencies are using the newest version:
[INFO]   commons-cli:commons-cli .......................................... 1.2
[INFO]   org.hamcrest:hamcrest-all ........................................ 1.1
[INFO] 
[INFO] The following dependencies in Dependencies have newer versions:
[INFO]   junit:junit ............................................... 4.4 -> 4.7
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL

 

 

 

 

Of course, plugins are in the same boat, so you might also want to run mvn versions:display-plugin-updates to check which plugins have more recent versions available. While it's at it, it will also let you know if any plugins don't have their versions specified (which is generally not a good idea):

$ mvn versions:display-plugin-updates
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'versions'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Game of Life business logic module
[INFO]    task-segment: [versions:display-plugin-updates]
[INFO] ------------------------------------------------------------------------
[INFO] [versions:display-plugin-updates {execution: default-cli}]
[INFO] 
[INFO] The following plugin updates are available:
[INFO]   maven-checkstyle-plugin .................................. 2.2 -> 2.4
[INFO]   maven-clean-plugin ....................................... 2.2 -> 2.4
[INFO]   maven-deploy-plugin ...................................... 2.4 -> 2.5
[INFO]   maven-surefire-report-plugin ........................... 2.4.3 -> 2.5
[INFO]   org.codehaus.mojo:findbugs-maven-plugin ................ 1.2 -> 2.3.1
[INFO] 
[WARNING] The following plugins do not have their version specified:
[WARNING]   maven-clean-plugin .......................... (from super-pom) 2.4
[WARNING]   maven-deploy-plugin ......................... (from super-pom) 2.5
[WARNING]   maven-site-plugin ........................... (from super-pom) 2.1
[WARNING]   maven-surefire-plugin ....................... (from super-pom) 2.5

 

 

 

 

But the Versions plugin doesn't just stop at reporting: you can also use it to actually update the version numbers in your pom.xml files. You do this via the mvn versions:set command. A bit like the Maven Release Plugin, but without the ceremony. In the following listing, we are upgrading our project version from 1.0.0-SNAPSHOT to 1.0.2-SNAPSHOT. This will update all of the versions in any modules as well, and also in any inter-module dependencies:

$ mvn versions:set -DnewVersion=1.0.2-SNAPSHOT
[INFO] ----------------------------------------------------------------------------------
[INFO] Building tweeter 1.0.0-SNAPSHOT
[INFO] ----------------------------------------------------------------------------------
[INFO] 
[INFO] --- versions-maven-plugin:1.2:set (default-cli) @ tweeter ---
[INFO] Searching for local aggregator root...
[INFO] Local aggregation root: /Users/johnsmart/Projects/Training/coding-dojos/wellington-coding-dojo/tweeter
[INFO] Processing co.nz.codingdojo.tweeter:tweeter
[INFO]     Updating project co.nz.codingdojo.tweeter:tweeter
[INFO]         from version 1.0.0-SNAPSHOT to 1.0.2-SNAPSHOT
[INFO] 
[INFO] Processing co.nz.codingdojo.tweeter:tweeter-core
[INFO]     Updating parent co.nz.codingdojo.tweeter:tweeter
[INFO]         from version 1.0.0-SNAPSHOT to 1.0.2-SNAPSHOT
[INFO] 
[INFO] Processing co.nz.codingdojo.tweeter:tweeter-services
[INFO]     Updating parent co.nz.codingdojo.tweeter:tweeter
[INFO]         from version 1.0.0-SNAPSHOT to 1.0.2-SNAPSHOT

 

 

 

 

But you might also want to update your dependency versions while your at it. If you want to update them all in one fell swoop, you can use the mvn versions:use-latest-versions command, as shown here:

$ mvn versions:use-latest-versions
[INFO] ----------------------------------------------------------------------------------
[INFO] Building tweeter 1.0.0-SNAPSHOT
[INFO] ----------------------------------------------------------------------------------
...
[INFO] artifact javax.servlet:jstl: checking for updates from Nexus
[INFO] artifact net.sourceforge.jwebunit:jwebunit-htmlunit-plugin: checking for updates from Nexus
[INFO] Updated net.sourceforge.jwebunit:jwebunit-htmlunit-plugin:jar:null:2.1 to version 2.4
[INFO] artifact javax.servlet:servlet-api: checking for updates from Nexus
[INFO] Updated javax.servlet:servlet-api:jar:null:2.4 to version 2.5
[INFO] artifact org.springframework:spring-mock: checking for updates from Nexus
[INFO] artifact org.springframework:spring-core: checking for updates from Nexus
[INFO] Updated org.springframework:spring-core:jar:null:2.5.6 to version 3.0.3.RELEASE
[INFO] artifact com.google.inject.extensions:guice-servlet: checking for updates from Nexus
[INFO] ------------------------------------------------------------------------------------------------

 

 

 

 

Other goals worth mentioning are mvn versions:use-latest-releases, which replaces SNAPSHOT dependencies with the latest release, if they are more recent, and mvn versions:use-releases, which replaces any SNAPSHOT dependencies that have been released with the corresponding release versions. So, if you run mvn versions:use-releases, if would update from version 1.0.0-SNAPSHOT to version 1.0.0, if it is available, whereas mvn versions:use-latest-releases would bump it up to 1.0.2 if there is a 1.0.2 available. There is also versions:use-next-snapshots and versions:use-latest-snapshots, which do the same thing for SNAPSHOT versions.

Finally, once your happy with your new versions, use mvn versions:commit to set your changes in stone. This removes the backup files that the Versions plugin has been keeping, just in case. And if you finally decide it was all a horrible mistake, just run mvn versions:revert, and you will be back to the state you started with. Easy as!

If you want to learn more about the finer points of build automation with Maven, and a heap of other interesting stuff, be sure to check out the Java Power Tools bootcamps, coming up real soon in London and Canberra. Check it out!

Categories: Blogs

Selenium 2/Web Driver - the land where Page Objects are king!

Mon, 08/09/2010 - 13:49

In the world of automated web testing, Selenium 2/WebDriver is the new kid on the block, but it is also arguably the most compelling web testing tool around at the moment. Selenium 2/WebDriver is the result of the merging of two popular open source web testing frameworks: Selenium 1 and WebDriver, in an effort to learn the lessons gleaned from both of these older libraries. And the teams have learned their lessons well, and come up with a slick, elegant and functional testing framework.

Selenium 2, like Selenium, is a cross-browser tool - it is equally happy to run through both Firefox and Internet Explorer. But it also works with HTMLUnit which simulates a browser by sending HTTP requests and analyzing the HTML responses. You can pick from several drivers, including HTMLUnit (which great for fast testing of more conventional web applications), as well as browser-based drivers for Firefox, Chrome and InternetExplorer. The basic API is identical, though milage will vary from one driver to another, particularly if you are testing AJAX-based applications - for example tests for some AJAX apps will work with the Firefox browser, but not with the HTMLUnit browser. The good news is that it is trivially simple to switch between drivers.

Setting up Selenium 2 in a Maven project is easy: just add the following dependency:

<dependency>
	<groupId>org.seleniumhq.selenium</groupId>
	<artifactId>selenium</artifactId>
	<version>2.0a5</version>
</dependency>
This will give you the Selenium 2 core libraries plus all of the drivers.

In Selenium 2, a simple web test might look like this:

@Test
public void theUserShouldBeAbleToTypeInQueryTerms() {
	WebDriver driver = new FirefoxDriver();
	driver.get("http://www.google.com");
	WebElement queryField = driver.findElement(By.name("q"));
	queryField.sendKeys("cats");
	queryField.submit();	
	assertThat(driver.getTitle(), containsString("cats"));		
}
In this test, Webdriver will start an instance of Firefox and open up a connection to Google. Next it will type the word "cats" into the query field (whose name attribute is 'q'). Finally we submit the enclosing form, and check that the page title now contains the word "cats".

Selenium users will notice that the API is much more object-oriented and reads more smoothly than the older Selenium 1 API. It is also simpler and easier to learn than the sizable Selenium API.

As mentioned earlier, the API is virtually identical, no matter what browser you are using. If you want to use HTMLUnit instead, you just change the driver:

@Test
public void theUserShouldBeAbleToTypeInQueryTerms() {
	WebDriver driver = new HTMLUnitDriver();
	driver.get("http://www.google.com");
	WebElement queryField = driver.findElement(By.name("q"));
	queryField.sendKeys("cats");
	queryField.submit();	
	assertThat(driver.getTitle(), containsString("cats"));		
}
Now, in the real world, there are exceptions, and at times you may want to use some of the more advanced features that only a browser-based driver such as the FirefoxDriver can offer: these include some AJAX features, drag-and-drop, and figuring out whether an object on the page is actually visible or not. But, in general, the API is effectively cross browser.

Another nice feature, when compared to Selenium 1, is the lack of ceremony required to execute the test. This test will work as-is, with no extra plumbing, infrastructure or hidden wires required. For an equivalent Selenium 1 test, you would need to start up a Selenium-RC server before running the test, which is a relatively slow and sometimes fickle process. In Selenium 2, this is no longer required - you can write this test in Eclipse and run it in isolation, and it will work just fine.

The findElement pattern that we saw earlier turns out to be an extremely powerful way of modeling and verifying web pages, and you can do things that you could only dream of in Selenium 1. For example, the following results table comes from an ICEFaces JSF application:

<table class="iceForm:iceTable">
  <tr>
  </tr>
  <tr class="bidTableRow oddRow">
    <td class="column1">ICEsoft Ice Sailor</td>
    <td class="column2">$10,000.00</td>
    <td class="column3">0</td>
    ...
  </tr>
  <tr class="bidTableRow evenRow">...</tr>
  <tr class="bidTableRow oddRow">...</tr>
  <tr class="bidTableRow evenRow">...</tr>
</table>
Suppose we wanted to verify in detail the contents of this table. In Selenium 2, findElement is a great to do this. You see, the findElement() method returns a WebElement object: once you have it, you can also use the findElement() method on this WebElement object, to drill down into the HTML contained within. For example, the following code extracts column values for each row in the table shown above:
WebElement table = driver.findElement(By.id("iceForm:iceTable"));
List rows = table.findElements(By.className("bidTableRow"));
for(WebElement row : rows) {
    String name = row.findElement(By.className("column1")).getText();
    String price = row.findElement(By.className("column2")).getText();
    String bids = row.findElement(By.className("column3")).getText();
    // Do something with the row data
}

But where Selenium 2 really shines is in its support for Web Objects. Web Objects are a technique that involves modeling your user interface in the form of classes, with meaningfully-named fields and methods. This makes the tests more readable by isolating them from the implementation details, and also allows a better use of a business-friendly vocabulary. Here is a simple Page Object, which models the Google search page:

public class GoogleSearchPage {

	protected WebDriver driver;
	
	private WebElement q;	

	private WebElement btnG;

	public GoogleSearchPage(WebDriver driver) {
		this.driver = driver;
	}
	
	public void open(String url) {
		driver.get(url);
	}

	public void close() {
		driver.quit();
	}
	
	public String getTitle() {
		return driver.getTitle();
	}

	public void searchFor(String searchTerm) {
		q.sendKeys(searchTerm);
		btnG.click();
	}

	public void typeSearchTerm(String searchTerm) {
		q.sendKeys(searchTerm);
	}
	
	public void clickOnSearch() {
		btnG.click();
	}
}

Although this class is not of much use in isolation, Selenium 2 provides a way to map it to a real web page. The PageFactory class provides a convenient way of initalizing the Page Object fields.

public class WhenAUserSearchesOnGoogle {

	private GoogleSearchPage page;
	
	@Before
	public void openTheBrowser() {
		page = PageFactory.initElements(new FirefoxDriver(), GoogleSearchPage.class);
		page.open("http://google.co.nz/");
	}

	@After
	public void closeTheBrowser() {
		page.close();
	}

	@Test
	public void whenTheUserSearchesForCatsTheResultPageTitleShouldContainCats() {
		page.searchFor("cats");
		assertThat(page.getTitle(), containsString("cats") );
	}	
}

By default, it will map Page Object properties to fields with matching ids or names, so the example given here will work fine out of the box. But sometimes we need more control over identifying elements in the HTML page and mapping them to our Page Object fields. One way to do this is to use the @FindBy annotation, as shown in the following code:

public class GoogleSearchPage {

	protected WebDriver driver;
	
	@FindBy(id="q")
	private WebElement searchField;	

	@FindBy(name="btnG")
	private WebElement searchButton;

	public AnnotatedGoogleSearchPage(WebDriver driver) {
		this.driver = driver;
	}
	
	public void open(String url) {
		driver.get(url);
	}

	public void close() {
		driver.quit();
	}
	
	public String getTitle() {
		return driver.getTitle();
	}

	public void searchFor(String searchTerm) {
		searchField.sendKeys(searchTerm);
		searchButton.click();
	}

	public void typeSearchTerm(String searchTerm) {
		searchField.sendKeys(searchTerm);
	}
	
	public void clickOnSearch() {
		searchButton.click();
	}
}

Selenium 2/Web Driver provides a host of powerful features in a very clean API - in fact, we've just scratched the surface in this article. In future articles, I will discuss testing AJAX applications with WebDriver, and writing your own test DSLs with WebDriver and BDD tools like easyb. So stay tuned! In the meantime, if you are serious about automated web testing, you really should try it out.

If you want to learn more about Selenium 2/WebDriver, be sure to check out the upcoming TDD/BDD training workshops (coming up in Canberra, Wellington, and Sydney), and the Java Power Tools bootcamps (coming up soon in London and Canberra) - both of these courses include brand-new Selenium 2/WebDriver. We are also running this module on request as a full-day course. Check it out!

Categories: Blogs

Testing JDK 1.4 production code using Java 5 tests in Maven

Mon, 08/02/2010 - 15:13

Java 5 marks a huge step forward in the realm of automated testing. JUnit 4, for example, introduces many powerful new features based on annotations, such as flexible test names and parameterized testing. TestNG has had very cool annotation-based features since its first release. And Selenium 2.0/WebDriver also has some great new features based on annotations that make it much easier to create Page Objects.

However there are still those of us who, usually for reasons beyond our control, need to deploy to a Java 1.4-based environment. So are you stuck with prehistoric unit testing tools and prehistoric testing practices? The answer is no - even deploying to an archaic JVM, you can still use these new features for your tests. Curious? Read on!

In fact, it's not too difficult, once you know how. The first thing you need to do is to configure the compiler options for each phase, to ensure that your application source code is compiled for Java 1.4, and your test code for Java 1.5. This isn't too hard: you can do it by configuring the maven-compiler-plugin as shown here:

<project...>
  <build>
    ...
	<plugins>
	  <plugin>
	    <groupId>org.apache.maven.plugins</groupId>
	    <artifactId>maven-compiler-plugin</artifactId>
	    <version>2.3.1</version>
	    <executions>
	      <execution>
	        <id>java-1.4-compile</id>
	        <phase>compile</phase>
	        <goals>
	          <goal>compile</goal>
	        </goals>
	        <configuration>
	          <source>1.4</source>
	          <target>1.4</target>
	        </configuration>
	      </execution>
	      <execution>
	        <id>java-1.5-compile</id>
	        <phase>process-test-sources</phase>
	        <goals>
	          <goal>testCompile</goal>
	        </goals>
	        <configuration>
	          <source>1.5</source>
	          <target>1.5</target>
	        </configuration>
	      </execution>
	    </executions>
	  </plugin>
      ...
    </plugins>
  </build>
  ...
</project>

This will ensure that your application code will fail to compile if any generics, enumerations or other Java 5 features slip in, but still allow you to use all of these features in your test code.

This is great, but we're not done yet. There are still some more subtle dangers. For example, the String class introduced the contains() method in Java 5. However, with the above configuration, if you use this method your code will still compile, but it won't run in a Java 1.4 environment.

The answer comes in the form of the somewhat strangely named animal-sniffer-maven-plugin. The Animal Sniffer Plugin lets you check your code against the signature of a given API, and in particular against the API of specific versions of the JDK. If you want to ensure that your code works against Java 1.4, you just need to add the following plugin configuration to your build section:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>animal-sniffer-maven-plugin</artifactId>
  <version>1.6</version>
  <configuration>
    <signature>
      <groupId>org.codehaus.mojo.signature</groupId>
      <artifactId>java14</artifactId>
      <version>1.0</version>
    </signature>
  </configuration>
  <executions>
    <execution>
      <phase>test</phase>
      <goals>
        <goal>check</goal>
      </goals>
    </execution>
  </executions>
</plugin>

The animal-sniffer-maven-plugin accepts values like java13, java14, java15 or java16. You can also be more precise if required - for example, java15-sun or java14-ibm.

So, if you want to try the new and cool annotation-based features of many modern automated testing frameworks, but still need to deploy to an antediluvian JVM in production, now you can!

If you want to learn more cool Maven build automation tricks and funky automated testing practices, be sure to check out the upcoming Java Power Tools Bootcamps, coming soon to Wellington, London and Canberra.

Categories: Blogs

Come learn to kick-butt in Java Build Automation, Automated Testing, Code Quality, CI and more!

Tue, 07/27/2010 - 10:21

Maven 3, Selenium 2/WebDriver, easyb, Hudson, and more! The next sessions of the Java Power Tools Bootcamps are coming up soon in Wellington, London, and Canberra. Don't miss out on this great opportunity to learn some very useful and very cool skills and best practices in the areas of build automation, code quality, automated testing and continuous integration.

This is always a popular course, and once again all of the modules have been extensively updated with new material. Some of the highlights of this season include:

  • Advanced Maven build automation, including automated releases, automated deployments, Nexus, and Maven 3
  • Code quality best practices: Checkstyle, PMD, FindBugs, Cobertura, Sonar, and how to make them work for your teams
  • JUnit Kung Fu, parameterized tests, theories, custom Hamcrest asserts, Custom JUnit test runners,
  • Automated web testing with Selenium 2/WebDriver, and Behavior-Driven Development/Acceptance Test Driven Development with easyb
  • Advanced Continuous Integration with Hudson, including automated code quality and code coverage metrics, parameterized build jobs, build promotion, automated deployment and distributed builds. 

The session dates are:

Places are limited, so what are you waiting for? Sign up now!

Categories: Blogs

Useful tricks in easyb - tags and parallel tests

Wed, 07/21/2010 - 19:50

Easyb is an excellent BDD testing framework, with a heap of very cool features. In this article, we look at two more recent features: tags and parallel tests.

If you're looking for a good Behavior-Driven Development (BDD) or Acceptance-Test Driven Development (ATDD), you owe it to yourself to check out Easyb. Easyb is a great BDD-style testing framework where you express your tests as "stories" and "scenarios", using a highly-readable form based on the familiar "given-when-then" structure. A simple story (containing a single scenario) is shown here:

scenario "transfer funds to a savings account",{
given "a current account containing $200"
and "a savings account containing $1000"
when "when I transfer $100 from the current to the savings account"
then "the current account should contain $100"
and "the savings account should contain $1100"
}

One of the nice things about easyb is that this is actually a fully executable easyb story - put it in a file called (say) TransferFunds.story, and easyb will be happy to run it, include in the easyb reports, and flag it as 'pending implementation'.

When you are ready to actually implement this story, you add the appropriate code into each step. For example, here is an example of an acceptance-test from a web application implementing Conway's Game Of Life:

before_each "assume that the user has seeded the universe", {
    given "that the application is up and running", {
        homePage = new HomePage(new HtmlUnitDriver())         
    }
    and "that the user has opened the 'new game' page", {
        homePage.open();
        newGridPage = homePage.clickOnNewGameLink()
    }
}

scenario "Generating a new generation of cells",{
    given "that the user enters a stable set of living cells", {
        newGridPage.clickOnCellAt(0,0)
        newGridPage.clickOnCellAt(0,1)
        newGridPage.clickOnCellAt(1,0)
        newGridPage.clickOnCellAt(1,1)
        gridDisplayPage = newGridPage.clickOnGoButton()
    }
    when "the user clicks on 'Next Generation'", {
        gridDisplayPage = gridDisplayPage.clickOnNextGenerationButton()
    } 
    then "the application will display a universe containing the same cells", { 
        String[][] theInitialGrid = [["*", "*", "."],
                                     ["*", "*", "."],
                                     [".", ".", "."]]
        gridDisplayPage.displayedGrid.shouldBe theInitialGrid
    }
}

Easyb also supports tags, which are a very flexible way of categorizing your stories. For example, you can use tags to identify stories related to a particular feature, or to identify the stories being implemented in the current sprint. Or you can use tags to identify a story with the corresponding issue in your issue tracking system. If you identify all of the stories in the current sprint, for example, you can easily set up a build configuration to run, and report on, just the stories for this sprint. Of course your full build would run all of your stories, but this special sprint-specific build is a great reporting tool to let you know which stories have been completed and which are still pending implementation.

Easyb tags are easy to use. You can add a tag to a story as shown here:

tags "transfers"

scenario "transfer funds to a savings account",{
given "a current account containing $200"
and "a savings account containing $1000"
when "when I transfer $100 from the current to the savings account"
then "the current account should contain $100"
and "the savings account should contain $1100"
}

scenario "transfer funds to a current account",{
  ...
}

You can put as many tags as you want on a story - here's an example of a story with two tags:

tags ["transfers", "sprint-2"]

scenario "transfer funds to a savings account",{
given "a current account containing $200"
and "a savings account containing $1000"
when "when I transfer $100 from the current to the savings account"
then "the current account should contain $100"
and "the savings account should contain $1100"
}

In the current version of easyb, you can only apply tags to stories, not scenarios - scenario-based tagging is planned for a future version.

The latest version of the Easyb Maven plugin (version 0.9.7-1) provides full support for tags. For example, you could run only the 'sprint-2' stories using the following configuration:

<build> 
  <plugins> 
    <plugin> 
      <groupId>org.easyb</groupId> 
      <artifactId>maven-easyb-plugin</artifactId> 
      <version>0.9.7-1</version> 
      <executions> 
        <execution> 
          <goals> 
            <goal>test</goal> 
          </goals> 
        </execution> 
      </executions> 
      <configuration> 
          <tags>sprint-2</tags> 
      </configuration> 
    </plugin> 
  </plugins> 
</build>

Another very useful trick is parallel testing. I use easyb extensively for acceptance tests, involving web tests or other end-to-end tests. With lots of I/O and database interaction, these tests are perfect candidates for being run in parallel. If you add the parallel configuration option, as shown below, easyb will create up to ten threads and run your stories in parallel:

<build> 
  <plugins> 
    <plugin> 
      <groupId>org.easyb</groupId> 
      <artifactId>maven-easyb-plugin</artifactId> 
      <version>0.9.7-1</version> 
      <executions> 
        <execution> 
          <goals> 
            <goal>test</goal> 
          </goals> 
        </execution> 
      </executions> 
      <configuration> 
        <tags>sprint-2</tags> 
        <parallel>true</parallel> 
      </configuration> 
    </plugin> 
  </plugins> 
</build>

But wait! There's more! Easyb is a dynamic project with some very smart dudes working on it, and there are some very cool new features are in the pipeline, including data-driven tests and JUnit-compatible reports! Watch this space!

If you want to learn more about BDD and ATDD, be sure to check out the upcoming Java Power Tools Bootcamps, coming up soon in Wellington, London and Canberra.

Categories: Blogs

The ultimate build notification strategy

Fri, 07/16/2010 - 08:44

Categories: Blogs

A new chapter of the 'Continuous Integration with Hudson' book is available.

Wed, 07/14/2010 - 06:12

A new draft chapter of the 'Continuous Integration with Hudson' book is now available online. This new chapter discusses automated testing with hudson, including unit, integration and performance testing. You can download the PDF version on the book web page. As usual, all comments are welcome! 

Categories: Blogs