Passing a list of strings to CFWheels’ findAll() where argument

Use the ListQualify() function to pass a list of strings to the where argument in CFWheels ORM finders. ListQualify() encloses each list element in with the string specified (in this case, a single quote). Without it, CFWheels interprets the list as a single value.

<cfscript>
names = "Foo,Bar";
users = model("User").findAll(where="firstname IN ('#names#')");
/*
 * Generates SQL Query.. Not so good
SELECT firstname, lastname FROM users WHERE firstname IN ('Foo,Bar')
*/

users = model("User").findAll(where="firstname IN (#ListQualify(names, "'")#)");
/* 
 * Generates SQL Query. Great success!
SELECT firstname, lastname FROM users WHERE firstname IN ('Foo','Bar')
*/
</cfscript>

Great success!

Advertisement

Ensuring Full Unit Test Coverage In Your CFWheels App

Ensuring that you have unit tested all (or most) of your code in your CFWheels app is an important part of any test suite. As you hopefully know by now, the CFWheels framework features an in-built unit test framework.

The code below is a test itself, that will scan your controllers, models and views folders and make sure that you have a corresponding “test” cfc for each. If it discovers that a test is missing, it will fail.. so your app will not pass unless it has full test coverage.

To get it working, just copy the code below and save it into a file in /tests/TestsExist.cfc (or anywhere under the tests folder actually). You can retro-fit it to any app, though you may need to re-organise your test files somewhat.

There are some conventions that you need to follow to have it work properly, but I consider this being well organised (and you should be used to conventions by now). Your folder structure under /myapp/tests/ should look like this... Say you have a Login.cfc controller, your controller test cfcs themselves should be named like this TestLogin.cfc.. but you could also have multiple test files for your Login.cfc, just as long as the file BEGINS with “TestLogin”, eg: TestLoginRedirects.cfc, TestLoginBusinessLogic.cfc.. you get the idea.

The same goes for models and views. There is much one could do to improve/re-factor/customise this code, but it will hopefully catch anything you may have forgotten to test. Feel free to contribute to this project on GitHub.

So to summarise:

  • Re-organise your folders as per the example above
  • Re-name your test cfc files using Test{YourControllerName}.cfc
  • Copy the code into a TestsExist.cfc file under the /tests/ folder
  • Run your unit tests
<cfcomponent extends="wheelsMapping.Test">
	
	<cffunction name="setup">
		<cfset testsPath = ExpandPath("tests")>
		<cfset controllersPath = ExpandPath("controllers")>
		<cfset modelsPath = ExpandPath("models")>
	</cffunction>
	
	<cffunction name="test_00_setup_and_teardown">
		<cfset assert("true")>
	</cffunction>

	<cffunction name="test_01_all_controller_tests_exist">
		<cfdirectory action="list" directory="#controllersPath#" filter="*.cfc" name="controllers" />
		<cfdirectory action="list" directory="#testsPath & '/' & 'controllers'#" filter="*.cfc" name="controllerTests" />
		<cfset assert("controllerTests.recordCount gt 0")>
		<cfloop query="controllers">
			<cfif ListFindNoCase("Controller.cfc,Wheels.cfc", controllers.name) eq 0>
				<cfset abbrev = ListFirst(controllers.name, ".")>
				<cfset isTestFileFound = false>
				<cfloop query="controllerTests">
					<cfif FindNoCase("Test" & abbrev, controllerTests.name) gt 0>
						<cfset isTestFileFound = true>
						<cfbreak>
					</cfif>
				</cfloop>
				<cfset assert("isTestFileFound", "controllers.name")>
			</cfif>
		</cfloop>
	</cffunction>
	
	<cffunction name="test_02_all_model_tests_exist">
		<cfdirectory action="list" directory="#modelsPath#" filter="*.cfc" name="models" />
		<cfdirectory action="list" directory="#testsPath & '/' & 'models'#" filter="*.cfc" name="modelTests" />
		<cfset assert("modelTests.recordCount gt 0")>
		<cfloop query="models">
			<cfif ListFindNoCase("Model.cfc,Wheels.cfc", models.name) eq 0>
				<cfset abbrev = ListFirst(models.name, ".")>
				<cfset isTestFileFound = false>
				<cfloop query="modelTests">
					<cfif FindNoCase("Test" & abbrev, modelTests.name) gt 0>
						<cfset isTestFileFound = true>
						<cfbreak>
					</cfif>
				</cfloop>
				<cfset assert("isTestFileFound", "models.name")>
			</cfif>
		</cfloop>
	</cffunction>

	<cffunction name="test_03_all_view_tests_exist">
		<cfdirectory action="list" directory="#controllersPath#" filter="*.cfc" name="controllers" />
		<cfdirectory action="list" directory="#testsPath & '/' & 'views'#" filter="*.cfm" name="viewTests" />
		<cfset assert("viewTests.recordCount gt 0")>
		<cfloop query="controllers">
			<cfif ListFindNoCase("Controller.cfc,Wheels.cfc", controllers.name) eq 0>
				<cfset abbrev = ListFirst(controllers.name, ".")>
				<cfset isTestFileFound = false>
				<cfloop query="viewTests">
					<cfif FindNoCase("Test" & abbrev, viewTests.name) gt 0>
						<cfset isTestFileFound = true>
						<cfbreak>
					</cfif>
				</cfloop>
				<cfset assert("isTestFileFound", "controllers.name")>
			</cfif>
		</cfloop>
	</cffunction>

	<cffunction name="teardown">
	</cffunction>

</cfcomponent>

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&amp;action=index&amp;

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!

JUnify Plugin for CFWheels

Make the CFWheels test framework return jUnit XML

JUnify will run your CFWheels unit tests, then return the results in jUnit formatted XML. Use it for automated testing with your Continuous Integration server.

Following the road to jUnit Glory

  • Download and install the JUnify plugin from CFWheels or GitHub
  • Create a JUnifyController.cfc controller that calls the JUnify() function*
  • Write some unit tests for your app or plugin
  • Make a call to your JUnify url

* Controller filename and action names are unimportant

JUnifyController.cfc

<cfcomponent extends="Controller">
	
	<cffunction name="index">
		<cfset JUnify(params)>
	</cffunction>
		
</cfcomponent>

Your JUnify URL
http://yourserver/index.cfm?controller=junifycontroller&action=index&type=app

Pay particular attention to the type parameter.
– type=app will run tests for your application
– type=myplugin will run tests for your plugin
– type=core will run tests for the CFWheels framework itself

Props to Rocketboots for their RocketUnit test framework

DatePicker Plugin for CFWheels

Use a jQuery UI datePicker widget in your CFWheels forms

datePicker and datePickerTag functions accept the same arguments as CFWheels textField and textFieldTag functions respectively, but they also accept all options for the jQuery datePicker widget

Following the road to DatePicker Glory

1. Install the DatePicker plugin from CFWheels or GitHub
2. Make sure you have setup jQuery AND jQuery UI in your app (consider my JQuack plugin)
3. Use the datePicker() and datePickerTag() form helpers

Examples

<!--- Use with objects --->
#datePicker(label="Birthday", objectName="user", property="birthday")#

<!--- Use without objects --->
#datePickerTag(label="Birthday", name="birthday", value=Now())#

Note: All jQuery specific arguments (jQuery datePicker options) are case-sensitive

CFWheels Plugin Function Argument Defaults

A handy and powerful CFWheels feature for keeping your code DRY is to be able to configure application-wide default for wheels functions.

It’s also possible to tap into the CFWheels framework to make this feature available to functions added by your own plugins. Here’s how.. (props to Andy Bellenie)

Let’s assume you have created a plugin called putOnWeight and in this plugin, you have a function called eatCake()

As per the CFWheels documentation you set your application-wide function defaults in your settings.cfm like so:

<!--- config/settings.cfm --->
<cfset set(functionName="eatCake", howMany=20)>

To have your plugin accept these function defaults, you will need to tap into the CFWheels $args() function.. like so:

<!--- plugins/PutOnWeight.cfc --->
<cfcomponent output="false" mixin="controller">

	<cffunction name="init">
		<cfset this.version = "1.1.7">
		<cfreturn this>
	</cffunction>

	<cffunction name="eatCake">
		<!--- note that howMany argument is not required, and has no default --->
		<cfargument name="howMany" type="numeric" required="false">
		<!--- use the CFWheels $args function to look for default arguments set in settings.cfm --->
		<cfset $args(name="eatCake", args=arguments)>
		<!--- cake.. nom nom nom! --->
		<cfset var loc = {}>
		<cfset loc.cakesEaten = arguments.howMany>
		<cfreturn loc.cakesEaten>
	</cffunction>

</cfcomponent>

Disclaimer: the $args() function is a private cfwheels framework function so use at your own peril… I am.

JQuack for jQuery CFWheels Plugin

Manage and call your jQuery core files, plugin packages, UI and themes with a set of JQuack functions. Download it here..

It also adds a simple UI for configuring all your core and plugins
This plugin adds a set of functions to call your jQuery core files, plugin packages, UI and themes. You can can also call files from an external library (Eg: Google CDN).

There is also my standalone CFC for use outside of CFWheels (but why would you want to do that?)

Contributions
Feel free to contribute via GitHub or drop me an email.. I have also written a bunch of unit tests if you’re into that sort of thing, they’re all available on GitHub.

Credits
Tony Petruzzi for his many replies to all things CFWheels, plugins and unit testing
CFWheels and jQuery for all-round awesomeness
JQuack Roadmap
Better support for external file requests
Support for non minified versions of UI files
File verification tool
Unit test improvements

Function Syntax
JQuackCore([coreFileName, rootURL, head])
JQuackPlugin([key, file, pluginRootURL, delimiter, head])
JQuackUI([UIBundleName, themeName, rootURL, delimiter, head])
JQuackTheme(themeName, [UIBundleName, rootURL, head])
JQuackAll([delimiter, head])

Recommended Usage Example

<!--- 1. include all files as defined in your JQuack configuration --->
#JQuackAll()#

<!--- 2. include minimal files --->
#JQuackCore()#
#JQuackPlugin("foo,bar")#
#JQuackUI()#

<!--- 3. include a combination of files --->
#JQuackCore()#
#JQuackPlugin("foo,bar")#
#JQuackPlugin(file="jquery.foo.js", pluginRootURL="http://www.foobar.com/plugins/")#
#JQuackUI(themeName="barfoo")#
JQuackCore()
Usage Example
<!--- JQuackCore() Examples --->
<!--- call the core file as defined in config --->
#JQuackCore()#

<!--- write the output to the head area of the HTML page --->
#JQuackCore(head=true)#

<!--- call a different version of the core file from your javascripts/jquery/ folder --->
#JQuackCore(coreFileName="jquery-1.5.0.min.js")#

<!--- call from Google Libraries API --->
#JQuackCore(coreFileName="jquery.min.js", rootURL="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/")#
JQuackPlugin()
Usage Example
<!--- JQuackPlugin() Examples --->
<!--- call a single plugin package --->
#JQuackPlugin("foo")#

<!--- call multiple plugin packages --->
#JQuackPlugin("foo,bar,quack")#

<!--- don't worry, none of the 'foo' files will be included more than once --->
#JQuackPlugin("foo,bar")#
#JQuackPlugin("foo")#

<!--- write the output to the head area of the HTML page --->
#JQuackPlugin(key="foo,bar", head=true)#

<!--- call all plugins --->
#JQuackPlugin()#

<!--- remove line breaks between included files --->
#JQuackPlugin(delimiter="")#

<!--- call a plugin package from another location --->
#JQuackPlugin(key="foo", pluginRootURL="http://someserver.com/js/plugins/")#
#JQuackPlugin(key="bar", pluginRootURL="/javascripts/someotherfolder/")#

<!--- call a file not defined in your packages but located in the /javascripts/jquery/plugins/ folder --->
#JQuackPlugin(file="jquery.foobar.js")#

<!--- call a file from another location --->
#JQuackPlugin(file="jquery.foobar.js", pluginRootURL="http://someserver.com/js/plugins/")#
JQuackUI()
Usage Example
<!--- JQuackUI() Examples --->
<!--- call the UI bundle as defined in config --->
#JQuackUI()#

<!--- include the UI with a different theme --->
#JQuackUI(themeName="rainy")#

<!--- include a different UI bundle --->
#JQuackUI(UIBundleName="jquery-ui-1.2.34.custom")#

<!--- write the output to the head area of the HTML page --->
#JQuackUI(head=true)#
JQuackTheme()
NOTE: This function is called within JQuackUI(), so should only be used to override the theme used in JQuackUI()

Usage Example
<!--- JQuackTheme() Examples --->

<!--- include a different theme --->
#JQuackTheme(themeName="wacky")#

<!--- write the output to the head area of the HTML page --->
#JQuackTheme(themeName="wacky", head=true)#
JQuackAll()
Usage Example
<!--- JQuackAll() Examples --->
<!--- include all files --->
#JQuackAll()#

<!--- include all files without line breaks --->
#JQuackAll(delimiter="")#

<!--- write all output to the head area of the HTML page --->
#JQuackAll(head=true)#

CFWheels Plugins and My Unit Testing Adventures!

Seeing as unit testing your CFWheels plugins has yet to be thoroughly documented, I thought I would share my experiences with writing a unit test suite for my jQuack plugin. Here is my take on writing well organised unit tests, I am by no means an expert. In fact before embarking on this project, I was a total unit test noob, but I learned valuable lessons from trial, error and much advice from Tony Petruzzi.

Unit tests are a set of repeatable tests that determine if your code meets its requirements. In a way, they also document your plugin’s behaviour as the tests themselves describe its requirements. Unit tests encourage you to write re-useable, modular code and are invaluable for checking that your plugin still function as designed when:

  • A new version of CFWheels is released
  • Testing across CFML engines
  • Expanding or refactoring your plugin

For more information on developing plugins for CFWheels, go here.. I will use my jQuack plugin as the basis for my examples, your plugins will of course need different types of tests.. but that’s why you get paid the big bucks!

But enough jibber jabber.. Let’s get testing fool!


1. Create a folder called “tests” in your plugin’s folder (eg /plugins/jquack/tests).
This is where your tests code, and any assets required for the tests will reside. This assets folder can (and should) mimic your application folder structure, but only create the folders you use in your tests (see the next step for how to use them). For jQuack, I needed an isolated bunch of assets (files, folders & variables) that I could butcher with my tests without affecting my actual application.

2. Create a Base.cfc in the tests folder and be sure to extend the wheels Test component.
This is not required, but I would consider it good practice and will make your test suite scalable. This cfc will contain tasks that are common to all of your tests, primarily for setup and teardown, but it may also contain helper functions that are used by your tests. This particular implementation of the setup and teardown methods are VERY important. At the start of each test, the setup method will be called, which will copy the existing application scope and massage it for this test. The test will then run and the teardown method will revert the application scope back to its original state. NOTE: The setup and teardown happens before and after EVERY test.. not just before and after the request. This isolated assets environment was probably the single most important concept for me, once I got this working, writing the actual tests was a breeze!

<cfcomponent extends="wheelsMapping.Test">

	<cffunction name="setup">
		<!--- save the orginal environment --->
		<cfset loc.orgApp = Duplicate(application) />
		<!--- path to our plugins assets folder where we will store our components and files --->
		<cfset loc.assetsPath = "plugins/JQuack/tests/assets" />
		<!--- repoint the lookup paths wheels uses to our assets directories --->
		<cfset application.wheels.controllerPath = "#loc.assetsPath#/controllers" />
		<cfset application.wheels.pluginPath = "#loc.assetsPath#/plugins">
		<cfset application.wheels.javascriptPath = "#loc.assetsPath#/javascripts" />
		<!--- we're always going to need a controller for our test so we'll just create one --->
		<cfset params = {controller="foo", action="bar"} />
		<cfset JQuackController = controller("jquack", params) />
	</cffunction>
	
	<cffunction name="teardown">
		<!--- recopy the original environment back after each test --->
		<cfset application = loc.orgApp />
	</cffunction>
		
</cfcomponent>

3. Create your unit tests cfc
Be sure to prefix the file with “Test” or it will be skipped. Also make sure to extend your Base.cfc AND call super.setup() and super.teardown() in this cfc. I like to number my tests so they run in the order specified. I also like to give my tests descriptive names. Don’t be afraid to break your tests up into separate packages. I have split mine up into TestData.cfc, TestMarkup.cfc and TestScaffold.cfc. I like to test simple variable names against each other (a eq b) rather than have my assert() methods all messy… see tests 04 and 05.

TestMarkup.cfc

<cfcomponent extends="Base">

	<!--- call the setup & teardown from Base.cfc --->
	<cffunction name="setup">
		<cfset super.setup()>
	</cffunction>
	
	<cffunction name="teardown">
		<cfset super.teardown()>
	</cffunction>
	
	<!--- make sure setup & teardown work --->
	<cffunction name="test_00_setup_and_teardown">
		<cfset assert('true') />
	</cffunction>

	<!--- no need for me to comment what this does.. the function name says it all --->
	<cffunction name="test_01_$renderMarkup_returns_js_markup">
		<cfset file = "test_01.js" />
		<cfset a = JQuackController.$renderMarkup(file) />
		<cfset b = $JSTag(file) />
		<cfset assert('a eq b') />
	</cffunction>

	<!--- same here --->
	<cffunction name="test_02_$renderMarkup_prevents_duplicate_rendering">
		<cfset a = JQuackController.$renderMarkup("test_03.js") />
		<cfset b = JQuackController.$renderMarkup("test_03.js") />
		<cfset assert('Len(b) eq 0', 'b') />
	</cffunction>

	<!--- and here --->
	<cffunction name="test_03_core_method_default_returns_correct_markup">
		<cfset a = JQuackController.JQuackCore() />
		<cfset b = $JSTag("#JQuackController.$JQueryDirectoryURL()##loc.config.coreFileName#") />
		<cfset assert('a eq b') />
	</cffunction>
	
	<!--- messy --->
	<cffunction name="test_04_messy_example">
		<cfset assert('JQuackController.JQuackCore() eq $JSTag("#JQuackController.$JQueryDirectoryURL()##loc.config.coreFileName#")') />
	</cffunction>
	
	<!--- sexy --->
	<cffunction name="test_05_sexy_example">
		<cfset a = JQuackController.JQuackCore() />
		<cfset b = $JSTag("#JQuackController.$JQueryDirectoryURL()##loc.config.coreFileName#") />
		<cfset assert('a eq b') />
	</cffunction>

	<!--- more tests go here --->

	<!--- private helper functions keep things DRY --->	
	<cffunction name="$JSTag" access="private">
		<cfargument name="file" type="string" required="true" />
		<cfreturn '<script type="text/javascript" src="#arguments.file#"></script>' />
	</cffunction>

</cfcomponent>

The above is a snippet only for demo purposes.. the full test suite is available using the links below.
Once you have written your tests, you should run them using the ‘Run Tests’ link next to the name of your plugin in the CFWheels debug area.

4. Gotchas
In order to test any private methods in your plugin, they will need to be made public.. I prefix my “private” (but public) methods with a $ as per the CFWheels framework convention.

<cffunction name="$CRLF" returntype="string" access="public">
	<cfreturn Chr(13) & Chr(10) />
</cffunction>

This plugin uses the mixin=“controller” attribute, I’ve not yet built a plugin with any other value.

These 2 settings are pretty handy..

<!--- In config/design/settings.cfm --->
<cfset set(overwritePlugins=false)>
<cfset set(deletePluginDirectories=false)>

The JQuack plugin and its test suite is available for browsing or download from GitHub or from the CFWheels plugins directory.

Some handy links :
CFWheels Testing Framework
Writing Great Unit Tests
Creating CFWheels Plugins

Please comment if there are any parts that are unclear and I will try to clarify.

jQuack Coldfusion Component for jQuery

Update: JQuack is now a Coldfusion on Wheels plugin!

A CFC wrapper for including jQuery core files, plugins, UI components and themes. Explicitly including jQuery files is no big deal, but jQuack’s strength is being able to bundle a plugin’s core and any dependencies into a single function call with a single parameter (or no parameter at all!)

Is a dependency shared between plugins (e.g. bgiframe.js)? No problem, jQuack prevents files from being included more than once per request.

It makes application-wide or server-wide version changes simple.

Download it @ GitHub

Example Plugin Package Structure

<!--- Setup your plugin packages (structure of arrays) --->
<cfset pluginStruct = {} />
<cfset pluginStruct.foo = ["foo/foo.js","foo/foo.css"] />
<cfset pluginStruct.bar = ["bar/bar.css","bar/bar.js","bar/foobar.js","jquery.barfoo.js"] />
<cfset pluginStruct.CFJS = ["cfjs/jquery.cfjs.packed.js"] />

Example init params

<cfset initArgs = {} />
<!--- Name of the jQuery core file --->
<cfset initArgs.coreFileName = "jquery-6.6.6.min.js" />
<!--- URL Path to your javascript directory, defaults to /jquery/ --->
<cfset initArgs.rootPath = "/jquery/" />
<!--- Name of the jQuery UI bundle --->
<cfset initArgs.UIBundleName = "jquery-ui-1.0.0.custom" />
<!--- Name of the theme directory --->
<cfset initArgs.themeName = "sunny" />
<!--- 	URL Path to your plugins directory, defaults to /{rootPath}/plugins/ --->
<cfset initArgs.pluginPath = "/jquery/plugins/"	/>
<!---
A structure of arrays. Plugins will be reference by their structure key,
the array will contain URLs to the plugin files relative to the {pluginPath}
See Example pluginStruct above
--->
<cfset initArgs.pluginStruct = pluginStruct />
<!--- Intialising jQuack --->
<cfset jQuack = CreateObject("component","{your_cfc_path}.jQuack").init(argumentCollection=initArgs) />

Example Function Calls

<!--- Calling jQuack in your views --->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
	<head>
		<title>jQuack..</title>
		#jQuack.core()#
		#jQuack.plugin("foo,bar,cfjs")#
		#jQuack.ui()#

		<!--- a different core file --->
		#jQuack.core("jquery-6.6.6.min.js")#

		<!--- from an external URL --->
		#jQuack.core(coreFileName="jquery.min.js", rootPath="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/")#

		<!--- a single plugin --->
		#jQuack.plugin("foo")#

		<!--- multiple plugins --->
		#jQuack.plugin("foo,bar")#

		<!--- ALL plugins --->
		#jQuack.plugin()#

		<!--- a plugin not defined in the pluginStruct --->
		#jQuack.plugin(file="outbackjack/outbackjack.js")#

		<!--- a plugin from an external URL --->
		#jQuack.plugin(file="penelopepitstop.js", pluginPath="http://plugins.wackyraces.com/")#

		<!--- UI with a different theme --->
		#jQuack.ui(themeName="rainy")#
	</head>
	<body>...</body>
</html>

Example Directory Structure

Core File
/{yourWebRoot}/jquery/
/{yourWebRoot}/jquery/jquery-1.0.0.min.js

Plugins
/{yourWebRoot}/jquery/plugins/
/{yourWebRoot}/jquery/plugins/foo/
/{yourWebRoot}/jquery/plugins/foo/foo.js
/{yourWebRoot}/jquery/plugins/foo/foo.css
/{yourWebRoot}/jquery/plugins/bar/
/{yourWebRoot}/jquery/plugins/bar/bar.js
/{yourWebRoot}/jquery/plugins/bar/bar.css

UI & Themes
/{yourWebRoot}/jquery/jquery-ui-1.0.0.custom/
/{yourWebRoot}/jquery/jquery-ui-1.0.0.custom/css/
/{yourWebRoot}/jquery/jquery-ui-1.0.0.custom/css/sunny/
/{yourWebRoot}/jquery/jquery-ui-1.0.0.custom/css/sunny/images/
/{yourWebRoot}/jquery/jquery-ui-1.0.0.custom/css/sunny/jquery-ui-1.0.0.custom.css

/{yourWebRoot}/jquery/jquery-ui-1.0.0.custom/css/rainy/
/{yourWebRoot}/jquery/jquery-ui-1.0.0.custom/css/rainy/images/
/{yourWebRoot}/jquery/jquery-ui-1.0.0.custom/css/rainy/jquery-ui-1.0.0.custom.css
/{yourWebRoot}/jquery/jquery-ui-1.0.0.custom/js/jquery-ui-1.0.0.custom.min.js