Home | About Us | Stelligent  

TestEarly Weblog

Brothers


Stelligent Incorporated
Code Complexity and Publications and Agile and /Brothers12 May 2008 02:55 pm

I don’t always agree with Mr. Yegge, but this is a great presentation/script on Dynamic Languages with some very interesting ideas and discussion topics.

One point that he never actually got to, but one that I think is worth more discussion - how do you maintain a million-line codebase w/out static types?

My answer is that with a good dynamic language, you have some seriously elegant features and patterns that allow you to keep the size of your codebase small.  Essentially, you don’t maintain a million-line codebase - because it doesn’t take a million lines to write your application.

Which fits in with some of the agile concepts as well - if you are building a project in an agile style, the constant refactoring and removal of technical debt will keep the application smaller and lighter.  The unit tests ensure a clean level of separation of concerns, the DRY and YAGNI principles reduce bloat.

Developer Testing and /Brothers30 Apr 2008 02:21 pm

We had a proxy problem with Selenium RC today. The site-under-test is behind a proxy, and has the same domain name as the production site (let’s call it shop.mystore.com). Normally, developers set their proxy server in their browser, which then causes requests for shop.mystore.com to go to the proxy server which then sends the request to the developer site-under-test, instead of going to the production site.

We want to set up Selenium so the developers can created automated tests around visiting the site-under-test.

Selenium does have the ability to do a “double proxy”, using system properties:

java -Dhttp.proxyHost=proxy.server.com -Dhttp.proxyPort=3128 -jar selenium-server.jar

But it turns out, unfortunately, that this doesn’t seem to work in practice. After some investigation of my own, I discovered that the proxy configuration file (proxy.pac) in Selenium is not generated properly.  My own tests, and a timely visit to this discussion of the proxy chaining issue, it appears that there’s a simple workaround:

java -Dhttp.proxyHost=proxy.server.com -Dhttp.proxyPort=3128 -jar selenium-server.jar -avoidProxy

Setting -avoidProxy causes the proxy configuration (proxy.pac) to work properly, sending the selenium requests to the developer site-under-test.

Code Coverage and /Brothers23 Apr 2008 02:43 pm

This was discovered with Clover 2.2.1

We have a build.xml file with the following pseudo-flow:

  • clover-setup
    • // this causes all future compilations to use the clover compiler to instrument the files.
  • compile
    • javac _all_source_
  • test_A
    • javac _unit_test_source_ // yes, this is a subset of all source
    • junit _unit_tests_

  • test_B
    • javac _unit_test_source_ // yes, this is a subset of all source, and redundant with test_A
    • junit _integration_tests_
  • clover-report
    • NO DATA!

By inserting < clover-log / > at the end of test_A and test_B, I figured out what was going on.

  1. after test_A, we have a nice coverage level
  2. but at the end of test_B, we have been reset back to 0

My hypothesis is that there is a bug in Clover that causes it to:

a) wipe out all of the coverage data thus far when new code is compiled.

b) prevent new code from updating the coverage database.

And sure enough, by removing the javac compilation step from test_B, we have an accurate combined coverage report.

Moral of the story:

  1. Do all of your compiling before you run any of your automated tests
  2. < clover-log / > is your friend.
Build Management and Continuous Integration and /Brothers17 Apr 2008 12:23 pm

Let’s say you have a fairly complicated build structure, with multiple batch files that fire off different aspects of the build (even if, at the end of the day, they just call ant).

And let’s assume that for various historical reasons, these batch files encapsulate their environment variables using SETLOCAL and ENDLOCAL.

At first glance, this is a pretty cool way to scope out your environment variables. But then, you find out that Hudson determines if a build has succeeded or failed by looking at the %ERRORLEVEL% environment variable. If it is not 0, the build has failed.

Uh oh. Your build is failing, but the moment ENDLOCAL is called, %ERRORLEVEL% is set back to its previous value, which, most likely, will be 0.

Given this situation, how do you get the %ERRORLEVEL% back up to Hudson? Well, don’t call ENDLOCAL. Instead use:

EXIT %ERRORLEVEL%

at the end of your batch file. This works because there’s an implicit ENDLOCAL at the end of your batch file, and EXIT will return the ERRORLEVEL as the exit value.

Developer Testing and /Brothers11 Apr 2008 09:48 am

So you want to build a set of automated tests using Selenium against your webapp. I’m going to assume you have already figured out how to launch your app and set the database into a known state.

Now, you want to write some tests that mimic visiting the website and interacting with the UI in various ways.

I’ve been playing with Selenium quite a bit recently, and I’ve assembled a short list of things that will hopefully make other people’s lives easier.

Building your Tests : Navigation

  • Use Selenium IDE (Firefox Plugin) to develop the navigation flow for you. The last thing you want to be doing is debugging your navigation steps in your test case so you can get to the target. With Selenium IDE, you get your app running, and record the clicks and actions you take to get to your destination.
    • When you finish recording, you can export your test as a java program, or in several other languages. Take advantage of this!
  • To click on a link - if you assume you have a link like: < a xhref=" Your Text Here < / a > you can get the Selenium browser object to activate the link by issuing browser.click(”Your Text Here“);

Building your Tests: Validating Results

Selenium has XPath support, and XPath is a very powerful tool for processing HTML. But the syntax of XPath is quite arcane, and I spent waaaaaay too much time trying to decipher what was wrong with my XPath query.

  • Use XPath Checker (firefox plugin) - go to the results page, and control-click to bring up the XPath Checker browser. Then you can experiment with various XPath expressions until you get the one that works for your particular page and content.
  • To find if text appears anywhere on the page (also known as the quick-and-dirty method) - use assertTrue(browser.isTextPresent(”Your Text Here“));
  • To find if text appears in a specific sub-location, the easiest way I have found is:
    • assertEquals(”Text“, browser.getText(”//table[@id=’whatever’]//tr[2]/td[1]”));
    • Selenium is smart about pulling all of the text out of a set of cells, subtags, whatever, so even if that text was nested inside a div, a span and a link, it would still find it.

Running Your Tests

  • You can’t use Selenium inside your tests unless the Selenium RC Server is running - launch it before you start your tests, like you would Cargo, your database, etc.
  • It’s a proxy, so you have to make sure that the port you use in your code (default: 4444) is the same as the port that Selenium server is running on.

Hopefully this will help some future person get up to speed faster.

Continuous Integration and /Brothers24 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