Dec 22008
In a previous post on the topic of using the MXUnit eclipse plugin with virtual hosts, I described how I setup my eclipse project and Apache virtual host for testing. Although that setup worked, I would get periodic errors that necessitated disabling and re-enabling the MXUnit plugin. Until recently, I was still running eclipse 3.2, so when I got the opportunity to configure a new machine from the ground up, I decided to go with a fresh install of the latest eclipse (3.4) and essential plugins, CFEclipse (1.3.1.6), Subclipse (1.4.5) and MXUnit (1.0.7).
Read more...
Sep 82008
Confidently unit testing code that relies on a database is troublesome. There are many different approaches and many opinions on the matter. I've previously written about using transactions to safely rollback the database after every test. This worked well for me at the time, but there are pitfalls in using that approach. Recently, I've done some more research on the subject and even attempted, without success, to integrate DBUnit into my database reliant unit tests. After some trial and error, I landed on the following approach that is a culmination of a few ideas I'd previously heard of, but never tried. The goal of this approach is to:
- Run tests against a known data set.
- Reset the entire database prior to each test.
The example code that follows requires a test database, test database user and a test datasource targeting the test database.
Read more...
Aug 282008
Like the title says, this post will include code samples for setting up an
MXUnit test case using
ColdSpring and
ColdMock. The goal of any test case are to isolate the component under test as much as possible. I find ColdMock to be a simple and powerful tool for achieving test isolation. For this example, I created a test case for my ConfigFactory which I mentioned in a
previous post. TheConfigFactory component has a constructor dependency on the
Environment Config component developed by Rolando Lopez which makes this a good case for mocking.
Here's a snapshot of the files used in this sample test setup,

A common convention for test cases is to add the suffix "Test" to match the test case to the component being tested. I have my own convention for setting up tests withColdSpring bean definitions which I keep in a similarly named xml file. All test cases extend the BaseTestCase which contains a couple of methods to simplify test configuration with ColdSpring. The full code of the of the BaseTestCase follows.
<cfcomponent displayname="tests.BaseTestCase" extends="mxunit.framework.TestCase" output="false">
<cfset variables.beansXML = "">
<cffunction name="setBeanFactory" access="private" output="false" returntype="void">
<cfargument name="beansXML" type="string" required="true">
<cfargument name="params" type="struct" required="false" default="#structnew()#">
<cfscript>
if ((not structkeyExists(request,"beanFactory")) or (comparenocase(variables.beansXML,arguments.beansXML) neq 0))
{
variables.beansXML = arguments.beansXML;
request.beanFactory = createObject("component" ,"coldspring.beans.DefaultXmlBeanFactory").init(StructNew(),arguments.params);
request.beanFactory.loadBeans(variables.beansXML);
}
</cfscript>
</cffunction>
<cffunction name="getBeanFactory" access="private" output="false" returntype="any">
<cfreturn request.beanFactory>
</cffunction>
</cfcomponent>
In the past I kept my ColdSpring reference in variables scope, but I found that when testing components based that rely on Transfer ORM, I can shave the time of tests considerably when I have multiple tests in the same test case. Whether you run the MXUnit HttpAntRunner, the eclipse plugin or a manually configured test suite within a browser they all run as a single request, so as you define more tests it helps to speed things up.
Here's what the ConfigFactoryTest.xml looks like.
<beans>
<bean id="mockFactory" class="tests.MockFactory" singleton="true" />
<bean id="EnvironmentConfig" factory-bean="MockFactory" factory-method="createMock">
<constructor-arg name="objectToMock">
<value>model.Environment</value>
</constructor-arg>
</bean>
<bean id="ConfigFactory" class="model.ConfigFactory">
<constructor-arg name="hostName">
<value>${hostName}</value>
</constructor-arg>
<constructor-arg name="environmentConfig">
<ref bean="EnvironmentConfig" />
</constructor-arg>
</bean>
</beans>
You can see how easy it is to mock the dependency using the ColdMock MockFactory. Below is the full code for my ConfigFacotry test case. The important thing to note is that the component display name is used to resolve the path to the ColdSpring bean definitions used in the test suite.
<cfcomponent displayname="tests.ConfigFactoryTest" extends="tests.BaseTestCase">
<cffunction name="setUp" access="public" returntype="void">
<cfset var beanDefFileLocation = expandPath('/' & Replace(GetMetadata(this).displayname,'.','/','all') & '.xml')>
<cfset var params = Structnew()>
<cfset params.hostName = "www.somedomain.com">
<cfset setBeanFactory(beanDefFileLocation,params)>
</cffunction>
<cffunction name="testGetSetting" access="public" returntype="void">
<cfscript>
var configFactory = "";
var env = getBeanFactory().getBean("EnvironmentConfig");
var settings = structNew();
settings["MyString"] = "my string";
env.mockMethod('getEnvironmentByUrl').returns(settings);
configFactory = getBeanFactory().getBean("ConfigFactory");
assertTrue(configFactory.getSetting("MyString") eq settings["MyString"]);
</cfscript>
</cffunction>
<cffunction name="testGetAllSettings" access="public" returntype="void">
<cfscript>
var configFactory = "";
var env = getBeanFactory().getBean("EnvironmentConfig");
var settings = structNew();
settings["MyString"] = "my string";
env.mockMethod('getEnvironmentByUrl').returns(settings);
configFactory = getBeanFactory().getBean("ConfigFactory");
assertTrue(StructCount(configFactory.getAllSettings()) eq 1);
</cfscript>
</cffunction>
<cffunction name="testOnMissingMethod" access="public" returntype="void">
<cfscript>
var configFactory = "";
var env = getBeanFactory().getBean("EnvironmentConfig");
var settings = structNew();
settings["MyString"] = "my string";
env.mockMethod('getEnvironmentByUrl').returns(settings);
configFactory = getBeanFactory().getBean("ConfigFactory");
assertTrue(configFactory.getMyString() eq settings["MyString"]);
</cfscript>
</cffunction>
</cfcomponent>
Most of my tests aren't this involved. Since my ConfigFactory has a constructor dependency on EnvironmentConfig, I pull it out of ColdSpring first, mock the getEnvironmentByUrl method to return a known structure before requesting the ConfigFactory. Truly powerful stuff!
I have attached a zip file of this sample test bed as an enclosure for folks to try out.
Mar 92008
If you are into Unit Testing and haven't yet heard of
MXUnit, I definitely recommend giving it a whirl. Some things that stand out for me, thus far in my evaluation, are the simple, but extensible, assertions, the ecplise plugin, and the debug output. One gotcha that has come up for people when using the eclipse plugin, is that is was designed assuming that the package path to your components resolves directly from your web root. For people who run separate server instances, virtual machines, or develop locally with Apache virtual hosts, this is a show stopper. Luckily, for folks, like myself, who prefer to develop locally with Apache, getting the MXUnit eclipse plugin to work is simply a matter of adding a couple of Alias directives to your vhost.
Read more...
Recent Comments