Aliaspooryorik
ColdFusion ORM Book

Unit Testing ORM with ColdBox 3 and MXUnit

I've just started building a new site using Coldfusion 9's ORM capabilities. Being a good developer (OK, so I'm not but I aspire to be!) I created my tests directory and then hit the problem of how do I actually test Persisted Entities using MXUnit in a ColdBox 3 application?

The problems I had were that my Application.cfc in the root extends the coldbox.system.Coldbox, which I didn't want for testing. Also, the model folder (with all my CFCs in) was a sub folder of the application root - at the same level as my "_tests" folder. The other problem I had was test data. My directory structure looks like this (I like to prefix folders that I don't want in production with an underscore):


/ (web root)
/myproject/ (application root)
/myproject/Application.cfc (extends coldbox.system.Coldbox)
/myproject/_tests/ (folder for my MXUnit tests)
/myproject/model/ (this is where my CFCs to test are)

To solve the issues, I created a Application.cfc in the _tests folder which creates mappings to the model folder. I decided that I would uses the namingstrategy orm setting to force ColdFusion to create the database tables prefixed with "TEST_" so that I could hack away at the data without worrying about breaking the actual applications data.

Here is my _tests/Application.cfc


/**
* I am the Application.cfc for the _tests directory
*/

component
{

this.name = "tests_" & Hash( GetDirectoryFromPath( GetCurrentTemplatePath() ) );
this.sessionManagement = true;
this.sessionTimeout = createTimeSpan( 0, 0, 30, 0 );
this.setClientCookies = true;

// this file is in a directory at the same level as my model folder so need a mapping
this.mappings["/model"] = Replace( GetDirectoryFromPath( GetCurrentTemplatePath() ), "\_tests", "" ) & "model/";

// set up ORM
this.datasource = "mydsn";
this.ormenabled = true;
this.ormsettings = {
cfclocation = this.mappings["/model"],
namingstrategy = "TestNamingStrategy",
dbcreate = "dropcreate",
sqlscript = "testdata.sql"
};

public boolean function onRequestStart( string targetpage )
{
// ORMReload();
return true;
}

}

As you can see I specify an sql script to execute which populates from test data. I also point to a TestNamingStrategy.cfc, to create the alternative database table names. Here it is (note that I had to set the access to remote for MXUnit to call those methods):


component implements="cfide.orm.INamingStrategy"
{
/**
* Defines the table name to be used for a specified table name. The specified table name is either
* the table name specified in the mapping or chosen using the entity name.
*/

remote string function getTableName( string tableName )
{
// prefix table names with "TEST_"
return "TEST_" & UCase( arguments.tableName );
}
/**
* Defines the column name to be used for a specified column name. The specified column name is either
* the column name specified in the mapping or chosen using the proeprty name.
*/

remote string function getColumnName( string columnName )
{
// leave as is
return arguments.columnName;
}
}

I then added a RemoteFacade.cfc file so that I can use MXUnit from inside Eclipse.


component extends="mxunit.Framework.RemoteFacade"
{
}

To use this you need to right click on the project in Eclipse, select "properties > MXUnit properties" and enter the URL to the RemoteFacade.cfc. Mine looks like http://localhost/myproject/_tests/RemoteFacade.cfc.

Finally, ColdBox 3 supports MXUnit so I created a BaseTest to define common settings which all my unit tests extend. This BaseTest.cfc extends coldbox.system.testing.BaseTestCase


component extends="coldbox.system.testing.BaseTestCase"
{

public void function setup()
{
// set the path from the *web* root
setAppMapping( "/myproject" );
super.setup();
}

}

That's it, I don't know if this is a good solution or not, but it works for me!


5 comments

  1. Thanks for you post. I'll give the naming strategy a shot!

    Comment by Aaron Greenlee – June 02, 2010
  2. Great idea! Couldn't you also use a different datasource?

    Also, with ORM, what do you end up testing? Things like "entityLoad" are what they are and other than making sure _something_ loads, it doesn't seem that valuable of a test.

    Thanks.

    Comment by James Brown – October 10, 2010
  3. @James, yes you could. The downside to doing that is CFBuilder doesn't give you database insight as it doesn't know which DSN to use.

    I often test the Service Layer, so I'm testing all the components that the service uses. I like to do this sort of integration testing more than testing of individual components in isolation. For example if I'm testing a login, I want to make sure that the user is found in the database, that they are logged in and they have x,y and z permissions, until I log them out. Then I'd test that they have no longer have any permissions.

    Comment by John Whish – October 13, 2010
  4. Thank you John! This was very helpful. In a coldbox app, what do you unit test besides the service layer?

    Comment by JP Revel – November 13, 2010
  5. @JP Revel, in an ideal world - I test everything in isolation! :)
    However if I'm working to a really tight deadline I'd write the tests for the services and then when I have more time add in the tests for individual components

    Comment by John Whish – November 16, 2010

Leave a comment

If you found this post useful, interesting or just plain wrong, let me know - I like feedback :)

Please note: If you haven't commented before, then your comments will be moderated before they are displayed.

Please subscribe me to any further comments
 

Search

Wish List

Found something helpful & want to say ’thanks‘? Then visit my Amazon Wish List :)

Categories

Recent Posts