Automated Testing with CFWheels, Jenkins & Ant Tutorial

Automated Testing / Continuous Integration sounds complex and intimidating, but its like brain surgery.. its not that hard once you know the concepts and how the different elements fit together. Well maybe brain surgery wasn’t such a good example.. but you get the idea. Just think of a CI server as a fancy scheduled task manager.. with a few extra bits & pieces bolted on.

One of my pet projects this year has been to completely automate the testing and build of a CFWheels application. This guide is a bare-bones, no-frills installation to get you up and running. Assuming you already have written your unit tests, you should be able to get this up and running in under an hour.

There are many ways to skin this cat, but for this example I have used Jenkins as the CI server, Git as the version control system and Ant to do the builds. All elements are open source, so you can get up and running for zero dollars. I’m sure there are arguments for or against these choices and it’s quite possible to substitute any of them with your preferred method. There are an extensive array of plugins available for different source control flavours and build ‘tools’ (Ant, Maven, Command Line). My installation is on a 64bit version of Windows 7 using default installation paths.

Ideally, you would have a dedicated CI server which has its own application server (ColdFusion/Railo) and database. This is not essential.. in fact, my working example was installed on my laptop.. the only drawback with having the installation on your development machine, it that you will have to deploy your app to your webroot using a different foldername. Eg: “{webroot}/wheelsapp” source code will have to be deployed to “{webroot}/wheelsorama” so it can be tested without affecting your source code.

If you wanted to make your configuration even simpler, you could remove the Git repository configuration, and just run the unit tests directly on your source code.. but this is not ideal. * Be VERY careful with taking this approach as the example build script deletes the destination app folder before each deployment.. and that would be bad mmkay.

The example below will enable you to test your application, your plugins, the core wheels framework or a combination of the three (see the build.xml file).

Software Installation

As a general rule, I have install all software in their default locations, as you will see in the Jenkins configuration steps.

1. Install Java JDK
2. Install Ant (I recommend Winant if you’re on Windows)
3. Install Git
4. Install Jenkins

Windows users may need to re-boot (surprise surprise!) if the Jenkins service is not running (Check your Windows Services to confirm), if the service still fails to start, you may need to execute this from a command prompt (Run as administrator) An inconvenient workaround!

cd C:\Program Files (x86)\Jenkins
java -jar jenkins.war --ajp13Port=8010

5 .Visit your Jenkins server at http://localhost:8080 (or port 8010 if you had to start Jenkins via the command prompt)

You should have a brand-spanking new Jenkins server with which to unleash your automated wrath!

Configure Jenkins

1. Click “Manage Jenkins” > “Manage Plugins” > “Available” Tab
2. Find the Git Plugin and install it
3. Click the “Installed” tab and ensure you have the Git and Ant plugins. (Ant plugin should be bundled with the Jenkins install)

4. Return to the Jenkins dashboard and click “Manage Jenkins” > “Configure System”
5. In the JDK section, uncheck the “Install automatically” option and enter a name and the path to your JDK folder.

6. In the Git section, uncheck the “Install automatically” option and enter the path to your git executable

7. In the Ant section, click the “Add Ant” button, uncheck the “Install automatically” option and enter a name and the path to your Ant folder (or WinAnt if installed).

Create your Job

1. Return to the Jenkins dashboard and click “New Job”
2. Enter a job name and select “Build a free-style software project”

3. Under the “Source Code Management” section, check the “Git” option
4. Specify your app’s Git repository. If you are unfamiliar with this, it’s time to click here. This can be a local path, a network path or an ssh address.

5. Under the “Build Triggers” section, choose your preferred build interval. I like to have Jenkins poll my SCM (Git repository)  for changes every few minutes and build automatically if it finds any commits since the last build. */5 * * * * means every 5 minutes.. Click on the help icon for more info about intervals.

6. Under the build section, click the “Add Build Step” button and select the “Invoke Ant” option. Select the “Default Ant” configuration you added earlier. Since we will be using the default Ant convention (using build.xml), this is all that’s required.. but more about that shortly.

7. In the Post-build action section, click the “Add post-build action” button and select the “Publish JUnit test result report” option. Specify where your unit test result xml files will be written to. In this case build-report/test_result_*.xml, a folder called build-report with the files being called test_result_{something}.xml. Don’t worry too much about any warning messages here.. as the folders don’t exist yet.

Prepare your Wheels app 
There are a few steps here..

  • Initialise your wheels app as a Git repository
  • Download the JUnify Wheels plugin (the most dangerous plugin in the galaxy) which will return your unit tests in JUnit format (Ties in very nicely with Jenkins)
  • (Optional) Download the DBMigrate plugin for making automated database changes during the build
  • Now we need to tell Ant what to do to build and test your app. We will do this by creating 2 files in your app’s root folder. The 2 files are ant.properties and build.xml. ant.properties is for setting variables for use in build.xml. build.xml tells Ant what to do. * You will most likely need to modify the ant.properties file to suit your environment

ant.properties

# for running start/stop bat files
railo_bin=C:/railo/tomcat/bin
# cf_bin=C:/ColdFusion9/bin
# your webroot.. where jenkins will deploy your code (Apache/IIS)
web_root_dir=C:/railo/tomcat/webapps/ROOT
# web_root_dir=C:/inetpub/wwwroot
# where jenkins will git pull your code.. then deploy from
jenkins_workspace_dir=C:/Program Files (x86)/Jenkins/jobs/Wheels-O-Rama Deploy/workspace
# where jenkins will deploy to
destination_app_dir=${web_root_dir}/wheelsorama
# where unit test results will be written to
build_report_dir=${jenkins_workspace_dir}/build-report
# your app's url
app_root_url=http://localhost:8888/wheelsorama/index.cfm
# the unit test base url
unit_test_url=${app_root_url}?controller=JUnify&action=index&

build.xml

<project default="initialize">

	<!-- this is the default target (function) -->
	<target name="initialize">

		<!-- import properties -->
		<property file="ant.properties" />

		<!-- stop railo service.. not always needed! -->
		<!-- <exec dir="${railo_bin}" executable="cmd" os="Windows NT">
			<arg line="shutdown.bat"/>
		</exec> -->

		<!-- once jenkins has pulled the code into its workspace, i want to delete the previous deployment, but keeping root folder -->
		<mkdir dir="${destination_app_dir}" />
		<delete includeemptydirs="true">
			<fileset dir="${destination_app_dir}" includes="**/*" />
		</delete>

		<!-- then get a fresh copy of the latest code into the webroot for testing -->
		<copy todir="${destination_app_dir}">
	    	<fileset dir="${jenkins_workspace_dir}"/>
	    	<!-- exclude any files you don't want/need -->
	    	<!-- <exclude name="**/.gitignore"/> -->
	    	<!-- <exclude name="**/*.php"/> -->
	    	<!-- <exclude name="**/*.asp"/> -->
		</copy>

		<!-- make a folder in the workspace to keep my build reports -->
		<mkdir dir="${build_report_dir}" />

		<!-- start railo service -->
		<!-- <exec dir="${railo_bin}" executable="cmd" os="Windows NT">
			<arg line="startup.bat"/>
		</exec> -->

		<!-- migrate database using a call to the dbmigrate plugin url -->
		<!-- <get src="${app_root_url}?controller=wheels&amp;action=wheels&amp;view=plugins&amp;name=dbmigrate&amp;password=yourpassword&amp;migrateToVersion=999999999" dest="${build_report_dir}\dbmigrate_result.html" /> -->

		<!-- make a get request to your unit test url, writing the result to a file. Jenkins will use it to determine the success of your build
			== possible type param values ==
			# type=app		: runs the tests in /myapp/tests
			# type={myplugin}	: runs the tests in /myapp/plugins/{myplugin}/tests
			# type=core		: runs the tests in /myapp/wheels/tests
		-->
		<get src="${unit_test_url}type=app" dest="${build_report_dir}\test_result_app.xml" />
		<!-- <get src="${unit_test_url}type=myplugin" dest="${build_report_dir}\test_result_myplugin.xml" /> -->
		<!-- <get src="${unit_test_url}type=core" dest="${build_report_dir}\test_result_core.xml" /> -->

	</target>

</project>

Unit Tests

This is the final piece of the puzzle. The Wheels team have done a great job documenting unit testing your app using the Wheels test framework, and there is a post by someone about unit testing your plugins.. So get on it.

Build your app

Now that you are all configured and unit tests written.. its time to build! Click on the “Wheels-O-Rama Deploy” job then in the left menu click “Build Now”. You should see a progress bar appear under the menu.. it should either return a blue (good) or red (bad) icon. If you mouseover the build link and click the “Console Output” link you will see the output that was produced by Jenkins & Ant. You can watch the console output in real time by clicking the link whilst the build is in progress. If the build fails, this is where you will find the clues to its resolution.

Umm.. so WTF is actually happening?

I’m glad you asked..

  • Jenkins polls your Git repository looking for commits
  • When a commit it found, it will pull your source code into its workspace
  • Jenkins will use Ant to run your build.xml file which will…
    • Delete the previous code deployment from your webroot
    • Copy the latest source code from Jenkins workspace into your webroot
    • Call your unit tests via a URL and write the results to the Jenkins workspace
  • Jenkins will analyse the unit test results
  • Jenkins will report whether the build passed or failed

Where to from here?

This post is really just a minimal working example of automated testing. Here are a few ideas to play around with:

  • Setup a post build action to alert you of build failures
  • Break the existing job into separate “Deploy” and “Test” jobs (using a “Post Build Action” to kick off the Test job)
  • Build and test with different CFML engines, CFWheels framework versions and database engines for wide compatibility
  • Use the dbmigrate plugin to automatically make database changes upon building (See build.xml example)
  • Create another job that uses Ant to FTP your successful build to your production server
  • Use Selenium to do automated functional browser testing
  • Push your successful build to GitHub
  • Extending Jenkins further with the smorgasbord of plugins. The Chuck Norris plugin is a favourite of mine!

Feel free to comment regarding your experiences using this guide.. Thanks for reading!

8 thoughts on “Automated Testing with CFWheels, Jenkins & Ant Tutorial

  1. I thought I was going to the beach this weekend. Now I have no choice but to automate the framework tests for CFWheels since you made it so easy!

    Joking aside, this is an invaluable walkthrough that you have written. I can’t thank you enough for not only putting it together but also creating the JUnify plugin so this can be accomplished. Thank you once again.

  2. Thanks great work. Got unit testing and dbmigrate running from your posts. One quesion: How are you reporting on dbmigration success or failure? I did not see that in the build file.

    • Hi Rod, I’m glad this guide was helpful. There is no testing of the dbmigrate call in the build file. This guide is really just a bare bones concept. However, you may be able to either use a separate job in Jenkins to process the dbmigrate request or use the ant file to check the response. Please let me know how you go!

  3. Got it! Tougher than I thought. I wanted to have Jenkins/Ant handle all possible conditions, which can be: no migrations available, load error in an available migration, or general server error preventing the plugin from loading or something, and of course a pending migration. Just getting the available version was tricky. THEN same thing again: apply the migrations, and make sure nothing broke – mainly server errors and the like. And of course each invocation should report the status of the current database, and produce some build reports for any trouble shooting. Here is some sample output:

    D:\>ant -Dworkspace.path=. dbmigrate
    Buildfile: D:\build.xml

    dbmigrate:
    [echo] Check for DB migrations …
    [echo] Migrating to version 20130204220331

    doMigrations:
    [echo] Starting DB migrations
    [echo] Migration complete

    BUILD SUCCESSFUL
    Total time: 3 seconds

    and then, the same command reports this:

    D:\>ant -Dworkspace.path=. dbmigrate
    Buildfile: D:\build.xml

    dbmigrate:
    [echo] Check for DB migrations …
    [echo] There are NO migrations pending. Current database version is 20130204220331

    BUILD SUCCESSFUL
    Total time: 0 seconds

    Still need a bit of tweaking. Thanks again for inspiring better test automation and build supported migrations. Hope to get it integrates with Jenkins tomorrow.

Leave a reply to Rod Cancel reply