Neptune 1.0 Beta 1 Documentation: Tests

Neptune Information

Download from RIA Forge

Tests

One of the advantages of the way that Neptune uses data definitions, is that (outside of the data definitions) no additional code is needed in the model to manage the CRUD work. This is nice not only because it reduces the amount of work to create an application or the amount of code needed to run one, but because it helps identify business logic.

If you need to add any code to your model (and remember the view should only display and the controller should only translate data between the view and the model), then you are probably adding business logic to your application. If you are adding business logic to your application, then you need to have unit tests to verify your business logic is working as desired.

So, before you add any code to your model, write unit tests for it.

Writing the Unit Tests

First write down the business rules that you are trying to enforce. Once you know those, write a unit test stub for each business rule. The generator can write the stubs for you and RecordsTester.cfc can make writing the unit tests themselves easier.

Although unit testing is beyond the scope of this documentation, the basics are that you should write code that will verify that the business rule is being met and call a "fail" method (passing a string indicating what failed) if it doesn't. RecordsTester.cfc is itself based on (and requires) MXUnit.

You can add a user interface for your unit tests by using the "Rules" program that can be found on the Generator Program List page.

Example

For example, let's say that our client for Contact-O-Matic wants to make sure that any contact entered that has the name "Smithe" is saved with the name "Smith" instead (that spelling is just a pet peave of his, I guess).

We would first create a "tests" folder in our Contact-O-Matic application and then put a TestContactOMatic.cfc in it (all of this is just convention).

Here is TestContactOMatic.cfc with just a stub for the unit test:

<cfcomponent displayname="Contact-O-Matic" extends="com.sebtools.RecordsTester">

<cffunction name="setUp" access="public" returntype="void" output="no">
	
	<cfset loadExternalVars("ContactOMatic")>
	<cfset loadExternalVars(varlist="NoticeMgr",skipmissing=true)>
	
</cffunction>

<cffunction name="shouldSmitheBeRenamedSmith" access="public" returntype="void" output="no" hint="Any contact with the name 'Smithe' should have that name changed to 'Smith'.">
	
	<cfset runInRollbackTransaction(doshouldSmitheBeRenamedSmith)>
	
</cffunction>

<cffunction name="doshouldSmitheBeRenamedSmith" access="private" returntype="void" output="no">
	
	<cfset fail("Test not yet implemented")>
	
</cffunction>

</cfcomponent>

Change Alert!

Hopefully the "runInRollbackTransaction" functionality will not require a two methods per test in the future.

Now that we have our unit test stub, let's write the actual unit test itself. What we really need to do is save a record where the contact has a name of "Smithe" and then verify that it was changed to "Smith". So, here is the new "doshouldSmitheBeRenamedSmith" method:

<cffunction name="doshouldSmitheBeRenamedSmith" access="private" returntype="void" output="no">
	
	<cfset var sContact = {ContactName="James Smithe"}>
	<cfset var contactid = saveTestRecord(variables.ContactOMatic.Contacts,sContact)>
	<cfset var qContact = variables.ContactOMatric.Contacts.getContact(contactid)>
	
	<cfif qContact.ContactName NEQ "James Smith">
		<cfset fail("The name 'Smithe' was not renamed to 'Smith'.")>
	</cfif>
	
</cffunction>

The "saveTestRecord" takes a "Records" component (like "Contacts") and saves random data. If a structure is passed in for the data, then any keys in the structure will over-ride the randomly generated data.

We could also take advantage of the the "assertEquals" from MXUnit:

<cffunction name="doshouldSmitheBeRenamedSmith" access="private" returntype="void" output="no">
	
	<cfset var sContact = {ContactName="James Smithe"}>
	<cfset var contactid = saveTestRecord(variables.ContactOMatic.Contacts,sContact)>
	<cfset var qContact = variables.ContactOMatric.Contacts.getContact(contactid)>
	
	<cfset assertEquals(qContact.ContactName,"James Smith","The name 'Smithe' was not renamed to 'Smith'.")
	
</cffunction>

Now that we have written our unit test, we can go ahead and write our custom logic.

Next: Custom Logic