Performance Tip (Unit tests and ANT)

You've probably heard about the need to write unit tests before, and some of you may be religious about writing them. I won't get into all the how and why about unit tests. But...

I'll admit I've never been that good about writing unit tests for my CFML code. However, I should know better. We have over 15000 unit tests for ColdFusion, it's these tests that I depend on every day, especially when making changes that risk breaking backward compatibility in the language.

So tonight I was playing with CFUNIT and ANT. With this combination I was able to discover a serious deadlock issue. Finding a serious problem so quickly and in my first few tests has changed my mind about cfml unit tests. I will write them as soon as I can in every project and you should too.

In general unit tests are good for making sure you don't break functionality. But if something works with 1 users and not with 5 it's still broken. To test this, Ant has a tag called which will run the same task simultaneously in different threads. This is like running a stress load tests.

Note: You should still run a real-world load test against you application, before you put it into production, with a tool like OpenSta or Segue SilkPerformer. Using the unit tests will make sure that small chunks of code don't interfere with each other. Using a full load test tool makes sure the whole sections of the application don't interfere with each other and that your servers can handle the load you are expecting.

Here is the ANT build.xml I wrote to run my unit tests. To do a simple test of the functionality I run the "ant main" task and to test performance I run the "ant performance" task.

<?xml version="1.0"?>
<project name="CFUnit" default="main" basedir=".">
   <taskdef name="CFUnit" classname="net.sourceforge.cfunit.ant.CFUnit"/>
   
   <property name="domain" value="http://localhost:8500/web/applications/MyProject/" />
   
   <target name="main">
      <CFUnit testcase="${domain}components/users/test/UserBean.cfc" verbose="true" />
      <CFUnit testcase="${domain}components/users/test/UserDaoRead.cfc" verbose="true" />
      <CFUnit testcase="${domain}components/users/test/UserDaoCreate.cfc" verbose="true" />
      <CFUnit testcase="${domain}components/users/test/UserDaoCreate2.cfc" verbose="true" />
      <CFUnit testcase="${domain}components/users/test/UserDaoUpdate.cfc" verbose="true" />
      <CFUnit testcase="${domain}components/users/test/UserDaoDelete.cfc" verbose="true" />
      <!--
      -->

   </target>
   
   <!--
      Run the tasks 10 times with 5 threads
   -->

   <target name="performance">
      <parallel threadCount="5">
         <antcall target="main"/>         
         <antcall target="main"/>         
         <antcall target="main"/>         
         <antcall target="main"/>         
         <antcall target="main"/>         
         <antcall target="main"/>         
         <antcall target="main"/>         
         <antcall target="main"/>         
         <antcall target="main"/>         
         <antcall target="main"/>         
         <antcall target="main"/>         
         <antcall target="main"/>         
      </parallel>
   </target>
</project>

This might help too. This is the Ant build.xml I have in my root folder. This ant file includes all of the build.xml files in sub-folders. From here I can run all of my unit tests at once.

<?xml version="1.0"?>
<project name="CFUnit" default="main" basedir=".">
   <taskdef name="CFUnit" classname="net.sourceforge.cfunit.ant.CFUnit"/>
   
   <property name="domain" value="http://localhost:8500/web/applications/MyProject/" />
   
   <target name="main">
      <ant antfile="${basedir}/users/test/build.xml" dir="${basedir}/users/test" target="main">
         <property name="domain" value="${domain}"/>
      </ant>
      <ant antfile="${basedir}/products/test/build.xml" dir="${basedir}/products/test" target="main">
         <property name="domain" value="${domain}"/>
      </ant>
   </target>
   
   
   <target name="performance">
      <ant antfile="${basedir}/users/test/build.xml" dir="${basedir}/users/test" target="performance">
         <property name="domain" value="${domain}"/>
      </ant>       
      <ant antfile="${basedir}/products/test/build.xml" dir="${basedir}/products/test" target="performance">
         <property name="domain" value="${domain}"/>
      </ant>
   </target>
</project>

Comments
Micah Douglas's Gravatar Sorry to pollute your latest blog entry (I did read it) I don't have any comments on that today, but I did send you a fairly detailed e-mail on the whole Actionscript "keyword"" thing. Looking forward to a reply.
# Posted By Micah Douglas | 6/5/06 11:23 AM
Brian's Gravatar Mike, since this is fresh in your mind, perhaps you could write a short howto on what you need to acquire, install and how to run a simple unit test.

The part I don't understand (not having researched enough) is how to test bits realistically. For example, I have a saveMember() routine. It takes 10 parameters. Ideally I would test out of bounds, invalid datatypes, data that is too large, etc. How would I write a unit test using cfunit and ant to do this? Does it require writing 50 tests to cover all of the combinations?
# Posted By Brian | 6/5/06 1:01 PM
Nik's Gravatar I agree with Brian. I would love to see more info on how to write tests. Expecially when queries and custom objects are involved.
# Posted By Nik | 6/16/06 10:52 AM
top1's Gravatar If the empty element is at the end of the list split still ignors it.
# Posted By top1 | 4/14/08 1:05 AM
BlogCFC was created by Raymond Camden. This blog is running version 5.9.001.