In the last entry in this series on the Swiz framework, I discussed the use Dynamic Responders to make calls to the server as easy as possible. This entry is a short aside on how you can use some nice testing features that are built into Swiz to simulate calls to a server. As before, the current version of the application and its source code is available.

So far, we've looked at how Swiz's inversion of control (IoC) features make managing dependencies in a Flex application dead simple. We've dispatched events from the CentralDispatcher, and we've executed service calls using our Delegate class. But what is actually happening at the Delegate level? Let's delve into this.

You might have noticed that within my Controller, I'm having Swiz wire in an object of type IUserDelegate:

[Autowire]
public var delegate : IUserDelegate;
		

Why am I specifying the type as an interface instead of an actual class name? Flexibility! One of the most basic tenants of object-oriented design is to "design to interfaces". That doesn't necessarily mean you have to type everything as an interface. It just means you should keep your typing at the highest level of abstraction that you can. Ideally, that means typing things to interfaces or abstract classes.

Because I'm typing the delegate to IUserDelegate, that means I can have Swiz autowire anything that implements the contract defined by the IUserDelegate interface. And that's exactly what I'm doing. Here's the Beans.mxml file again:

<?xml version="1.0" encoding="utf-8"?>
<BeanLoader 
	xmlns="org.swizframework.util.*" 
	xmlns:mx="http://www.adobe.com/2006/mxml"
	xmlns:controller="com.briankotek.swizdemo.controller.*"
	xmlns:business="com.briankotek.swizdemo.delegate.*">

	<controller:UserController id="userController" />
	<business:MockUserDelegate id="userDelegate" />

</BeanLoader>
		

You can see that the delegate is actually a MockUserDelegate. Here's the code for that class:

package com.briankotek.swizdemo.delegate
{
	import com.briankotek.swizdemo.model.User;
	import mx.collections.ArrayCollection;
	import mx.rpc.AsyncToken;
	import org.swizframework.delegate.AbstractDelegate;
	import org.swizframework.util.TestUtil;

	public class MockUserDelegate extends AbstractDelegate implements IUserDelegate
	{
		
		// CONSTRUCTOR
		
		public function MockUserDelegate()
		{
			super();
		}
		
		// PUBLIC METHODS
		
		/**
		 * In a real application this would execute a server call to a remote object
		 */ 
		public function loadUsers() : AsyncToken
		{	
			return TestUtil.mockResult( buildMockUserCollection() );
		}
		
		/**
		 * In a real application this would execute a server call to a remote object
		 */ 
		public function saveUser( user : User ) : AsyncToken
		{
			if( !user.id )
			{
				user.id = Math.round( Math.random() * 100 );
			}
			return TestUtil.mockResult( user );
		}
		
		/**
		 * In a real application this would execute a server call to a remote object
		 */ 
		public function deleteUser( user : User ) : AsyncToken
		{
			return TestUtil.mockResult( user );
		}
		
		/**
		 * In a real application this might execute a call to a third party file server
		 */ 
		public function deleteUserProfileImage( user : User ) : AsyncToken
		{
			// Pretend that this deletes a file from a file server like Amazon S3.
			return TestUtil.mockResult( user ); 
		}

		// PRIVATE METHODS
		
		/**
		 * Build a fake collection of Users as a mock result.
		 */ 
		private function buildMockUserCollection() : ArrayCollection
		{
			var result : ArrayCollection = new ArrayCollection();
			
			var user1 : User = new User();
			user1.id = 1;
			user1.firstName = "Tom";
			user1.lastName = "Swift";
			result.addItem( user1 );
			
			var user2 : User = new User();
			user2.id = 2;
			user2.firstName = "Bob";
			user2.lastName = "Hope";
			result.addItem( user2 );
			
			var user3 : User = new User();
			user3.id = 3;
			user3.firstName = "Alan";
			user3.lastName = "Alda";
			result.addItem( user3 );
			
			var user4 : User = new User();
			user4.id = 4;
			user4.firstName = "Roger";
			user4.lastName = "York";
			result.addItem( user4 );
			
			return result;	
		}
	}
}
		

As you can see, I'm not actually making a call to a server. I'm generating an ArrayCollection of "fake" User objects, and then using a handy method called mockResult() in the Swiz TestUtils class. This method generates an AsyncToken for you and adds your result to it. It will even let you simulate a delay, like a real server call would have.

In this way, you can easily test your Swiz application without needing the server side working. This not only makes examples like mine much easier to release, but it lets you unit test your applications, as well as do work on parts of the UI before the server-side code has been implemented yet.

I hope you can see the usefulness of this approach, the handy nature of Swiz's mockResult() method, and the ease with which Swiz lets you swap out implementations like this. I'll sign off for now, but in the next entry (which will come more quickly than this one did, I promise) we'll look at another great Swiz feature: Dynamic Event Mediators.

Comments Comments (11) | del.ico.us del.icio.us | Digg It! Digg It! | Linking Blogs Linking Blogs | 8038 Views

Comments

  • # Posted By Steve Judd | 3/16/09 3:20 PM

    Brian, Thanks for this series. I'm well underway building a contact management system implemented in Flex and CF, and your articles have been a tremendous help in getting off the ground. Swiz rocks!

    Steve

  • # Posted By Gareth Arch | 3/17/09 3:52 PM

    That's great! I didn't even know about the TestUtils in Swiz.

  • # Posted By Tyler | 7/7/09 11:09 AM

    Thank you for this series. IoC aside, this one feature is enough to convinve me to try Swiz in my next project.

  • # Posted By Tyler | 7/7/09 11:10 AM

    Thank you for this series. IoC aside, this one feature is enough to convinve me to try Swiz in my next project.

  • # Posted By bud | 9/7/09 2:58 PM

    We get "The definition of base class AbstractDelegate was not found.   SwizDemo/src/com/briankotek/swizdemo/delegate   MockUserDelegate.as   line 11" error when trying to compile your example. Any advice?

  • # Posted By Gareth Arch | 9/8/09 9:57 AM

    The AbstractDelegate was removed from later versions of Swiz (as it wasn't doing anything). Take out the "extends AbstractDelegate" and (I think) it should work fine.

  • # Posted By D Edwards | 10/4/09 12:15 PM

    Brain this series has been one of the best detailed explanations of swiz I have been able to find so far. I am impressed with Chris in his foresight in this architecture it is clearly well thought out. I was feeling swiz inadequate after looking at Ben Clinkinbeard's SwizUserAdmin (a code example for which I was also grateful to view/study) and reading that he put that together after an hour of looking at swiz. Thank you for connecting some dots. I hope you find the time to finish this series as I see the last entry was over 6 months ago. It is making a difference and it is very much needed for new comers to the swiz environment. THANKS again.

  • # Posted By Mark | 11/30/09 4:59 PM

    I was about to say the same.

    --
    Mark Kwon
    http://www.venditascarpe.com

  • # Posted By Karthik | 12/16/09 6:53 AM

    Hi Brian,

    Great post -- shows how useful Swiz is for stubbing delegates.

    I have a follow-up question. How would we automate this mock delegate injection for unit testing? Let's say I have a component I want to test which is regularly hooked up to the real delegate. How would I, in the unit test code, instruct it to use the mock delegate? Or should I just have my test code manually set the mock delegate for the controller or whatever classes are using it?

    Cheers,
    Karthik

  • # Posted By Philip Bedi | 6/4/10 5:55 AM

    Which Flex SDK, I should use?

  • # Posted By Brian | 6/4/10 9:47 AM

    If you're using the 1.0 RC (http://www.briankotek.com/blog/index.cfm/2010/5/19...) it should work fine on Flex 3.3 and up, as well as Flex 4.