Recently I was helping to create a large domain model in UML. As the number of classes grew, I started thinking "man it's going to take a long time just to create all those CFCs, let alone their corresponding unit tests."
In response, I whipped up a simple generator to spit out stubbed CFC and CFUnit unit test files. I figured I'd share it to see if anyone else would get some use out of it.
Basically you just create a simple text file like this:
Person getName getAddress Invoice addLineItem calculateTotal
Then you run the generator like so:
<cfset cfcList = "/absolute/path/to/cfclist.txt" />
<cfset stubber = CreateObject('component','stubgenerator.CFCStubGenerator').init() />
<cfset stubber.createStubs(cfcList)" />
In the same directory as the text file, the generator will create stubs for each CFC and CFUnit file. So in this case, you'd get Person.cfc and Invoice.cfc:
<cfcomponent name="Person" hint=""> <cffunction name="init" access="public" output="false" hint="Constructor"> <cfreturn this /> </cffunction> <cffunction name="getName" access="public" output="false" hint=""> <cfthrow type="Unimplemented method" message="Method getName() in component Person not implemented yet." /> </cffunction> <cffunction name="getAddress" access="public" output="false" hint=""> <cfthrow type="Unimplemented method" message="Method getAddress() in component Person not implemented yet." /> </cffunction> </cfcomponent>
<cfcomponent name="Invoice" hint=""> <cffunction name="init" access="public" output="false" hint="Constructor"> <cfreturn this /> </cffunction> <cffunction name="addLineItem" access="public" output="false" hint=""> <cfthrow type="Unimplemented method" message="Method addLineItem() in component Invoice not implemented yet." /> </cffunction> <cffunction name="calculateTotal" access="public" output="false" hint=""> <cfthrow type="Unimplemented method" message="Method calculateTotal() in component Invoice not implemented yet." /> </cffunction> </cfcomponent>
And CFUnit files for TestPerson.cfc and TestInvoice.cfc:
<cfcomponent name="TestPerson" extends="net.sourceforge.cfunit.framework.TestCase">
<cffunction name="setUp" access="public" output="false" hint="">
<cfset var local = StructNew() />
<cfset variables.instance.Person = CreateObject('component','Person').init() />
</cffunction>
<cffunction name="test_getName" access="public" output="false" hint="">
<cfset var local = StructNew() />
<cfset fail('Test not yet implemented for method getName().') />
</cffunction>
<cffunction name="test_getAddress" access="public" output="false" hint="">
<cfset var local = StructNew() />
<cfset fail('Test not yet implemented for method getAddress().') />
</cffunction>
</cfcomponent>
<cfcomponent name="TestInvoice" extends="net.sourceforge.cfunit.framework.TestCase">
<cffunction name="setUp" access="public" output="false" hint="">
<cfset var local = StructNew() />
<cfset variables.instance.Invoice = CreateObject('component','Invoice').init() />
</cffunction>
<cffunction name="test_addLineItem" access="public" output="false" hint="">
<cfset var local = StructNew() />
<cfset fail('Test not yet implemented for method addLineItem().') />
</cffunction>
<cffunction name="test_calculateTotal" access="public" output="false" hint="">
<cfset var local = StructNew() />
<cfset fail('Test not yet implemented for method calculateTotal().') />
</cffunction>
</cfcomponent>
It will also create a file called testrunner.cfm that will create a test suite consisting of all of the generated tests, and then run them:
<cfset cfUnitRoot = "net.sourceforge.cfunit" />
<cfset tests = ArrayNew(1) />
<cfset ArrayAppend(tests, "tests.stubgenerator.components.TestPerson") />
<cfset ArrayAppend(tests, "tests.stubgenerator.components.TestInvoice") />
<cfset testSuite = CreateObject("component", "#CFUnitRoot#.framework.TestSuite").init(tests) />
<h1>Test Results</h1>
<cfset testSuite = CreateObject("component", "#CFUnitRoot#.framework.TestRunner").run(testSuite, 'Test Suite') />
That's it. I've attached a zip to this blog post, and will add this to the links pod in the sidebar. Feel free to let me know what you think. Thanks.
Comments (6) |
Download |
del.icio.us
|
Digg It!
|
Linking Blogs
| 4465 Views


# Posted By Sean Corfield | 7/26/06 11:25 AM
Nice. It would be even nicer if it targeted cfcUnit instead (cfcUnit is a nicer testing framework - more idiomatic for ColdFusion and a much cleaner code base). Paul's very close to releasing his ant task for it too - my team has cfcUnit automatically run all the test suites in Eclipse every time you change code - helps you find problems very quickly!
# Posted By Sami Hoda | 7/26/06 12:16 PM
Very impressive and useful!
# Posted By Brian Kotek | 7/26/06 2:38 PM
Thanks for the comments Sean. Yes, the main reason I've been using CFUnit is the ANT integration. I'll try to update this so that you can specify the unit testing framework as either CFUnit or CFCUnit and it will create either one.
# Posted By Chip Temm | 7/26/06 5:43 PM
Check out this project I started at http://cfopen.org/projects/openmodel/
It does the heavy lifting of parsing out the complicated UML XMI format into and easier-to-manipulate set of CF structs. From there it provides starter generators to create CFCs, unit test stubs, and SQL DDL (MS SQL for now, but extensible).
I keep meaning to rework it to help generate ModelGlue. Nobody has seemed remotely interested in this project, so I kind of put it aside for awhile.
# Posted By Robert Blackburn | 7/26/06 9:34 PM
This is great Brian - I will definitely be taking t a look at this and trying it out.
# Posted By Indy Nagpal | 5/21/08 2:44 PM
Thanks for your good work Brian.
I've been using the stub generator with cfunit and it's worked very nicely.
Just wondering if you are thinking of adding support for mxunit anytime soon? I'm thinking of switching to mxunit. Although mxunit has a built in generator, but to have the ability to generate tests only certain methods is a nice thing.