MXUnit: Unit Testing for Coldfusion

Posted on September 24, 2009

One of the things I got into recently is the whole idea of test-driven development (TDD). This concept puts testing at the core of development, at the start of the coding cycle and not after you finish coding. It’s definitely worth your while to read up on the good points of working this way, but to give you a few notable benefits of this approach:

  • By writing testing code first, that automatically fails, you can then proceed to improve and/or fix the code/class that it is testing, which then enforces refactoring of new code to meet the standards required

This tool works for pretty much all of the open-CFML engines, such as openbd and Railo, and this testing tool im talking about is MXUnit

 

Setting up MXUnit

You download the bundle from here and drop the mxunit folder into your web-root. It’s as simple as that. Any applications you have in your CF webroot would be able to access mxunit. If you use Eclipse, you can follow the instructions here to set up it’s very own plugin.

 

Adding tests to your project

Okay, so let’s say you have an existing project (although its best to start scratch if you want to be a true TDD programmer).  You would add a tests folder in your application, and this is where you will add the individual Test Cases, and Test Suites. 

Using Kent Beck’s TDD methodology we:

 

 

  1. Write the test first
  2. Watch the test fail
  3. Write the component
  4. Watch the test pass
so our first test -case, which we may store in a file called testUserManager.cfc. >

<cfcomponent displayname="testUserManager" extends="mxunit.framework.TestCase">

 <!--- StartUp(). Here we can add a new User --->

 <cffunction name="setUp" access="public" returntype="void">

 <cfset usermgrComp = createObject("component", "chickentrader.cfc.doronkatz.chickentrader.UserManager") />

 <!--- Create a random user --->

 <cfset user = CreateObject("component", "chickentrader.cfc.doronkatz.chickentrader.ObjectFactory").createUser()/>

 <cfset user.setActive("0")/>

 <cfset user.setEmail("doronsetup@doron#now()#")/>

 <cfset user.setPassword("testSetupPassword")/>

 <cfset user.setLanguage("E")/>

 <cfset user.setlastVisit("#DateFormat(now(),"yyyy-mm-dd")#")/>

 <cfset user.setRegDate("#DateFormat(now(),"yyyy-mm-dd")#")/> 

 <cfset user.setFirstName("Doron")/>

 <cfset user.setLastName("SetupTest")/>

 <cfset user.setCityName("Larnaca")/> 

 <cfset actual = usermgrComp.storeUser(user)/> 

 <!--- <cfset dump(user)/> --->

 </cffunction>


As you can see above, the startup() method when declared like that is used to temporarily create/setup data in the database, which will be used throughout this test, before being torn down later in this test case. So anything in this method is temporary. What I have done here is merely create a new object (since I enjoy using oop in my CFCs, and add properties to it. The actual gets assigned usermgrComp.storeUser(user) which essentially cascades to a component that actually does the qu erying, and returns back the status of whether it passed or not.  Note, we can use <cfset dump(user)>  which is a much better debugging method than cfdump, and introduc

ed

in MXUnit.

</div>

 

<cffunction name="testGetUserByID" access="public" returntype="void">

<cfset usermgrComp = createObject("component", "chickentrader.cfc.doronkatz.chickentrader.UserManager")/>

<cfset getAllUsers = usermgrComp.getUsers()/>

<cfset aUsersID = getAllUsers.user[1].id />

<cfset actual = usermgrComp.getUserById(aUsersID)/>

<cfset assertTrue(actual.user.id neq 0, "To ensure we have something returned back")>

</cffunction>

Our first test case (we always start function names wi

th ‘test’, and return void) creates a component and calls a method, we get values back. The important bit is towards the end where we have :

<cfset assertTrue….>

This is the assertion that we want to use to assert whether the value returned is equal to what we expect. We can use all sorts of assertions, and there are a few built-in ones that MXUnit provide to test true, pass, fail, same.

 <cffunction name="tearDown" access="public" returntype="void"> 

<cfset usermgrComp = createObject("component", "chickentrader.cfc.doronkatz.chickentrader.UserManager")/>

<cfset Users = usermgrComp.getUsers()/>

<cfset numUsers = arrayLen(Users.user)/>

<cfset aUser = Users.user[numUsers] />

<cfset actual = usermgrComp.deleteUser(aUser)/>

</cffunction>

The last function is TearDown(), which is the partner of StartUp(), and tears down the data we created, in StartUp(), so that we dont end up filling our database with useless junk. This is the cleanest way of ensuring we can run tests without having to unnecessarily populate our database.

Now that we have talked about the TestCase, a Test Suite is composed of many test cases, so we create the test suite. We don’t have to create a test suite if we just want to test a few minor things, but as best practice, I would start off by creating a suite and adding new test cases as we move on forward into our project. So I create a file called appTestSuite.cfm:

 

<cfparam name="URL.output" default="html">

<cfscript>

 testSuite = createObject("component","mxunit.framework.TestSuite").TestSuite();

//Load User object to test

testSuite.addAll("chickentrader.tests.testUserManager");

 results = testSuite.run();

</cfscript>

<cfoutput>#results.getResultsOutput(URL.output)#</cfoutput>  

<p><hr /></p>

<p>Using CFDUMP against <code>mxunit.TestResult.getResults()</code> method</p>

<cfdump var="#results.getResults()#" label="MXUnit Sample Test Results" />

As you can see we load the testUserManager test case we created earlier, here, and output the results. So we use this file as the entry point (unless you are using the plugin through eclipse) to view the results of your tests. When you see the results, you can see each test case, with a colouring to determine whether it passed, through either green or red. 

So this is the crash-course introduction to testing on coldfusion. Hopefully simple and quick enough, but you should visit the MXUnit website for more examples of how it is used.

 

 


No Replies to "MXUnit: Unit Testing for Coldfusion"


    Leave a Reply