Using the Swiz AutowiredTestCase

One of the utility classes that is part of the Swiz library is AutowiredTestCase. As the name implies, you can use this class to help test your Swiz applications.

In this case, code will show what's going on much better than doing a lot of typing, so here is a sample FlexUnit 4 test case. First, the class under test:

package com.briankotek.flex4swiztests.control
{
	import com.briankotek.flex4swiztests.event.MyEvent;
	import flash.events.IEventDispatcher;

	public class MyController
	{
		
		[Dispatcher]
		public var dispatcher : IEventDispatcher;
		
		public var didSomething : Boolean = false;
		
		[Mediate( event="MyEvent.CONTROLLER_ACTION_REQUESTED" )]
		public function handleAction() : void
		{
			didSomething = true;
			actionComplete();
		}
		
		private function actionComplete() : void
		{
			dispatcher.dispatchEvent( new MyEvent( MyEvent.CONTROLLER_ACTION_COMPLETE ) );
		}
		
	}
}
		

You can see this is a simple controller, which responds to the CONTROLLER_ACTION_REQUESTED event, updates a property, and then dispatches CONTROLLER_ACTION_COMPLETE. We want to test that the controller is responding to the correct event, property updating the property, and finally dispatching the completion event.

The event itself is a simple event class:

package com.briankotek.flex4swiztests.event
{
	import flash.events.Event;
	
	public class MyEvent extends Event
	{
		public static const CONTROLLER_ACTION_REQUESTED : String = "controllerActionRequested";
		public static const CONTROLLER_ACTION_COMPLETE : String = "controllerActionComplete";
		
		public function MyEvent(type:String)
		{
			super(type, true, false);
		}
	}
}
		

Finally, the test case itself:

package com.briankotek.flex4swiztests.control
{
	import com.briankotek.flex4swiztests.control.MyController;
	import com.briankotek.flex4swiztests.event.MyEvent;
	import org.flexunit.Assert;
	import org.flexunit.async.Async;
	import org.swizframework.core.*;
	import org.swizframework.utils.test.AutowiredTestCase;

	public class MyControllerTestCase extends AutowiredTestCase
	{	
		private var myController : MyController;
		
		[Before]
		public function setUp():void
		{
			myController = new MyController();
			
			swizConfig = new SwizConfig();
			swizConfig.eventPackages = "com.briankotek.flex4swiztests.event.*";
			
			beanProviders = [new BeanProvider( [myController] )];
		}
		
		[After]
		public function tearDown():void
		{
			myController = null;
		}
		
		[Test(async)]
		public function testControllerActionRequested() : void
		{
			Assert.assertTrue( "Controller property is already true.", myController.didSomething == false );	
			Async.handleEvent( this, swiz.dispatcher, MyEvent.CONTROLLER_ACTION_COMPLETE, checkEvent ); 
			swiz.dispatcher.dispatchEvent( new MyEvent( MyEvent.CONTROLLER_ACTION_REQUESTED ) );
		}
		
		private function checkEvent( event : Event, passThroughData : Object ) : void
		{
			Assert.assertTrue( "Controller property was not updated.", myController.didSomething == true );	
		}
		
	}
}
		

I start off setting up an instance of Swiz that my test can use. AutowiredTestCase has a method marked with [Before] metadata, so that FlexUnit runs it before each test. I create an instance of the class under test (MyController), then set the event packages on the SwizConfig. Finally, I place the MyController instance into a BeanProvider, so that Swiz will process it as a bean. This way, any Swiz metadata in MyController is processed.

The test method dispatches a CONTROLLER_ACTION_REQUESTED event. If all goes well, the mediated event in the controller should run, update the property, and then the controller will dispatch the completion event. Running the test produces a passing result, so everything is working as expected!

Note that because Swiz actually processes your test case itself as a bean, you can use Swiz metadata in your test if you want or need to. So injecting a dispatcher, mediating an event, or testing custom metadata processors are all possible as well.

Comments Comments (2) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 7108 Views

My IECFUG Presentation Recording and Files

Last Friday I gave a presentation to the Inland Empire ColdFusion User Group. It covered a range of topics: MXUnit, ColdMock, and elements of my RIAForge FormUtilities and ColdSpring Bean Utilities projects.

The presentation went well, I think. There are a few technical issues towards the end when they were trying to set up a microphone to get a Q&A going, but they are minor. I've linked to the files and the recording below in case anyone is interested in having a look. Thanks again to Sami, Luis, and the IECFUG for allowing me to present!

del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 7120 Views

Small Update to ColdMock

In response to a thread on the MXUnit forums about mocking, I've made a quick update to ColdMock. I added a method named methodCallCount(methodName) to the mock objects. This will return the number of times that the specified method has been called up to the current execution point. This might be useful if you are testing a component that makes calls to a mock object but doesn't return anything or returns void, to ensure that the call to the mock object actually happened as expected.

So you can do something like:

Call a method that retuns void: <cfset facade.doSomething() />
This call to facade.methodCallCount('doSomething') should be 1: #facade.methodCallCount('doSomething')#
		

I also added a debug method called coldMock_debug() to the mocked objects to view the internal variables scope aid in any debugging issues with mocking.

Happy mocking! nyah nyah! Oh, not that kind of mocking. ;-)

del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 5045 Views

Unit Testing Transfer Decorators with CFCUnit, BeanInjector, and ColdMock

Paul Marcotte asked me to post about how one might unit test a Transfer Decorator. So here you go Paul (and anyone else who might be interested) :-) .

To start with, basic testing of a Transfer Decorator is really no different than testing any other component. First, I set up a ColdSpring file to use for the test. Note that, depending on how many things you need to test and what you're testing, you can use the same ColdSpring file to test numerous things. In other words, you don't necessarily have to have a separate ColdSpring XML file for every test.

<beans>
	
	<bean id="transferFactory" class="transfer.transferFactory">
	   <constructor-arg name="datasourcePath"><value>/tests/transfer/testing/datasource.xml</value></constructor-arg>
	   <constructor-arg name="configPath"><value>/tests/transfer/testing/transfer.xml</value></constructor-arg>
	   <constructor-arg name="definitionPath"><value>/tests/transfer/testing/definitions</value></constructor-arg>
	</bean>
	
	<bean id="datasource" factory-bean="transferFactory" factory-method="getDatasource" />

	<bean id="transfer" factory-bean="transferFactory" factory-method="getTransfer" />
	
</beans>
		

From here, the unit test might look like this (I'm using CFCUnit but the approach in CFUnit would be similar):

<cfcomponent name="TestRegisteredUser" extends="org.cfcunit.framework.TestCase">
	<cffunction name="setUp" access="public" output="false" hint="">
		<cfset var local = StructNew() />
		<cfset local.config = '/tests/transfer/testing/coldspring.xml.cfm' />
		<cfset beanFactory = CreateObject('component', 'coldspring.beans.DefaultXmlBeanFactory').init() />
		<cfset beanFactory.loadBeansFromXmlFile(beanDefinitionFile=local.config) />
		<cfset setRegisteredUser(beanFactory.getBean('transfer').get('user', 2)) />
	</cffunction>
	
	<cffunction name="test_customDecoratorMethod" returntype="void" access="public" output="false" hint="">
		<cfset var local = StructNew() />
		<cfset assertEqualsString("This is a custom method in the Decorator.", getRegisteredUser().customDecoratorMethod(), 'Custom decorator response does not match expected value.') />
	</cffunction>
	
	<cffunction name="getRegisteredUser" access="private" output="false" hint="I return the RegisteredUser.">
		<cfreturn variables.instance.RegisteredUser />
	</cffunction>
		
	<cffunction name="setRegisteredUser" access="private" output="false" hint="I set the RegisteredUser.">
		<cfargument name="RegisteredUser" required="true" hint="RegisteredUser" />
		<cfset variables.instance.RegisteredUser = arguments.RegisteredUser />
	</cffunction>
	
</cfcomponent>
		

As you can see, you grab the Decorator from Transfer, and then are free to test the methods in the Decorator the same way you would test any other CFC method.

To take this further, you can actually mix a number of the techniques that I've talked about to handle more complex tests. In this example, I'm using the TDOBeanInjectorObserver to wire in a ValidatorFactory to my Decorator. However, to keep the test isolated to the Decorator, I'm using ColdMock to create a mock of the ValidatorFactory and injecting that into the Decorator:

<beans>
	
	<bean id="transferFactory" class="transfer.transferFactory">
	   <constructor-arg name="datasourcePath"><value>/tests/transfer/testing/datasource.xml</value></constructor-arg>
	   <constructor-arg name="configPath"><value>/tests/transfer/testing/transfer.xml</value></constructor-arg>
	   <constructor-arg name="definitionPath"><value>/tests/transfer/testing/definitions</value></constructor-arg>
	</bean>
	
	<bean id="datasource" factory-bean="transferFactory" factory-method="getDatasource" />

	<bean id="transfer" factory-bean="transferFactory" factory-method="getTransfer" />
	
	<bean id="validatorFactory" factory-bean="MockFactory" factory-method="createMock">
		<constructor-arg name="objectToMock">
			<value>tests.transfer.testing.ValidatorFactory</value>
		</constructor-arg>
	</bean>
	<bean id="MockFactory" class="coldmock.MockFactory" />
	
	<bean id="beanInjector" class="common.components.utility.BeanInjector">
		<constructor-arg name="debugMode"><value>false</value></constructor-arg>
		<constructor-arg name="suffixList"><value></value></constructor-arg>
	</bean>
	
	<bean id="TDOBeanInjectorObserver" class="common.components.transfer.TDOBeanInjectorObserver" lazy-init="false">
		<constructor-arg name="transfer">
			<ref bean="transfer" />
		</constructor-arg>
		<property name="beanInjector">
			<ref bean="beanInjector" />
		</property>
	</bean>
	
</beans>
		

This way, I can test any methods in the Decorator that actually rely on the ValidatorFactory by mocking the results from the ValidatorFactory method calls:

<cfcomponent name="TestRegisteredUser" extends="org.cfcunit.framework.TestCase">
	<cffunction name="setUp" access="public" output="false" hint="">
		<cfset var local = StructNew() />
		<cfset local.config = '/tests/transfer/testing/coldspring.xml.cfm' />
		<cfset beanFactory = CreateObject('component', 'coldspring.beans.DefaultXmlBeanFactory').init() />
		<cfset beanFactory.loadBeansFromXmlFile(beanDefinitionFile=local.config) />
		<cfset setRegisteredUser(beanFactory.getBean('transfer').get('user', 2)) />
	</cffunction>
	
	<cffunction name="test_customDecoratorMethodUsingValidator" returntype="void" access="public" output="false" hint="">
		<cfset var local = StructNew() />
		<cfset local.validator = beanFactory.getBean('validatorFactory') />
		<cfset local.validator.returns("This is the MOCKED ValidatorFactory method.") />
		<cfset assertEqualsString("This is the MOCKED ValidatorFactory method.", getRegisteredUser().customDecoratorMethodUsingValidator(), 'Custom decorator using validator response does not match expected value.') />
	</cffunction>
	
	<cffunction name="getRegisteredUser" access="private" output="false" hint="I return the RegisteredUser.">
		<cfreturn variables.instance.RegisteredUser />
	</cffunction>
		
	<cffunction name="setRegisteredUser" access="private" output="false" hint="I set the RegisteredUser.">
		<cfargument name="RegisteredUser" required="true" hint="RegisteredUser" />
		<cfset variables.instance.RegisteredUser = arguments.RegisteredUser />
	</cffunction>
	
</cfcomponent>
		

Just for reference, the Decorator I'm using in these test examples looks like this:

<cfcomponent hint="Registered User" extends="transfer.com.TransferDecorator" output="false">
	
	<cffunction name="customDecoratorMethod" access="public" returntype="string" output="false" hint="">
		<cfreturn "This is a custom method in the Decorator." />		
	</cffunction>
	
	<cffunction name="customDecoratorMethodUsingValidator" access="public" returntype="string" output="false" hint="">
		<cfreturn getValidatorFactory().validatorFactoryMethod() />		
	</cffunction>
	
	<cffunction name="getValidatorFactory" access="public" returntype="any" output="false" hint="I return the ValidatorFactory.">
		<cfreturn variables.instance.validatorFactory />
	</cffunction>
		
	<cffunction name="setValidatorFactory" access="public" returntype="void" output="false" hint="I set the ValidatorFactory.">
		<cfargument name="validatorFactory" type="any" required="true" hint="ValidatorFactory" />
		<cfset variables.instance.validatorFactory = arguments.validatorFactory />
	</cffunction>
	
</cfcomponent>
		

Hopefully that helps clear up how one might go about testing a Transfer Decorator. It also shows how you can use unit testing, ColdMock, and the Transfer Bean Injector together. Please let me know what you think or if you have any questions or comments about how I'm doing this.

Comments Comments (4) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 7562 Views

ColdMock and CFC Stub Generator Updates

Just a quick note about some updates to the RIAForge projects for ColdMock and the CFC Stub Generator.

ColdMock had an issue when trying to mock a method that was defined in a superclass of the target object. This has been corrected. It will also validate arrays of components as return types (i.e. User[]) (thanks to João Fernandes for contributing this fix).

The CFC Stub Generator has some significant additions as well. The tool now supports generating private and public properties if you define these in the UML. Public properties are set in the THIS scope, and associated cfproperty tags are created.

The tool also supports existing CFCs now. It will not overwrite existing components, but will still generate the other files (unit tests, ColdSpring, etc.). This will allow you to quickly generate unit tests for an existing set of components by spec'ing them out in UML.

You can also set up alternate package hierarchies in the tool to define paths to CFCs that are outside of your project (for example, Transfer), and mark a CFC as "active" in the UML tool to instruct the generator to use this path as opposed to the root path you defined for your main project. You must set up the alternate package path and set the base package for the alternate packages as "root" in the UML tool. In this way, the generator will know the proper paths to the external components for typing and ColdSpring path creation. Examples of this setup are included in the bookstore2.zuml/bookstore2.xmi files.

Finally, the tool now has an option to use ColdMock instead of generating staic mock CFC files, and configure the unit tests and the generated ColdSpring file to use the MockFactory to use in the unit tests (requires ColdMock and CF8).

Comments Comments (4) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 6097 Views

More Entries