I just stumbled across a little type conversion quirk within Flex. I haven’t tested this in-depth, so I may yet be proven wrong.

However….check this out:

var someVal:string = “true”;
var bool:Boolean;
bool = someVal as Boolean; // bool == false;
bool = someVal; // bool == true;

If you try to explicitly cast a string to Boolean, the casting appears to fail silently, leaving the Boolean with its default value of false.

However, if you leave it to the runtime to convert, the conversion works fine.

Ya learn something new every day!

billboard_feed_128x128.pngI just got the email, that I’ve been aggregated on MXNA. HOORAH!

I gotta admit, that I thought this would never happen, after Ryan Stewart punked us all with his april fools post.

I personally am a huge fan of MXNA, and read it several times a day. The bloggers whose posts are a part of the MXNA herd are all outstanding, so I’m amongst some fine company!

Note to self : Must actually post blogs now…

An important part of a good test suite is repeatability, and independance from external changes. Therefore, if your method loads data from an external source, that’s a real testing no-no.

However, using the features of dynamic classes in AS3 we can whip up a mock webservice which gives us a guaranteed result, every time.

Here’s the class:

package com.martypitt.testing.mockObjects
{
    import flash.utils.Dictionary;
    import flash.utils.flash_proxy;

    import mx.core.Application;
    import mx.core.mx_internal;
    import mx.messaging.messages.AsyncMessage;
    import mx.messaging.messages.IMessage;
    import mx.rpc.AbstractOperation;
    import mx.rpc.AsyncToken;
    import mx.rpc.events.ResultEvent;
    import mx.rpc.soap.WebService;

    use namespace flash_proxy;
    use namespace mx_internal;

    public dynamic class MockWebService extends WebService
    {

        /** The default response is returned if a call is made to a method that has not been explicitly
         * set using setResponse() */
        private var _defaultResult:Object;

        /** Determines bevahiour if a call is made to a method where the response has not been explicity set.
         * If true, an error is thrown.
         * If false (default) the defaultResponse is returned.
         * */
        private var _throwErrorIfResultNotSet:Boolean = false;

        private var _resultDictionary:Dictionary = new Dictionary();

        public function get defaultResult():Object {
            return _defaultResult;
        }
        public function set defaultResult(value:Object):void {
            _defaultResult = value;
        }

        /** responseDictionary holds a list of predefined methods and their associated responses.
         * */
        protected function get resultDictionary():Dictionary {
            return _resultDictionary;
        }
        protected function set resultDictionary(value:Dictionary):void {
            _resultDictionary = value;
        }
        public function get throwErrorIfResultNotSet():Boolean {
            return _throwErrorIfResultNotSet;
        }
        public function set throwErrorIfResultNotSet(value:Boolean):void {
            _throwErrorIfResultNotSet = value;
        }

        public function MockWebService(destination:String=null, rootURL:String=null)
        {
            super(destination, rootURL);
        }

        /** callProperty is called by the Flex / flash framework when something tries to access
         * a method or property of a dynamic object which has not been defined in code.
         * Here we override the default behaviour to return the correct response.
         * */
        override flash_proxy function callProperty(name:*, ... args:Array):*
        {
            var response:Object;
            var methodName:String = getLocalName(name);

            switch (true) {
                case (_resultDictionary[methodName] == null && throwErrorIfResultNotSet) :
                    throw new Error(String(methodName) + ” does not have an appropriate result set.”);

                case (_resultDictionary[methodName] == null && !throwErrorIfResultNotSet) :
                    response = defaultResult;
                    break;

                case (_resultDictionary[methodName] != null) :
                    response = _resultDictionary[methodName]
                    break;

                default :
                    throw new Error(”Unhandled switch case scenario in MockWebService”);
            }

            var message:IMessage = new AsyncMessage()
            var token:AsyncToken = new AsyncToken(message)

            // We want to return the Async token now (just like a normal webservice would)
            // but we get the app to dispatch the ResultEvent on the next frame

            // It’s important that the result event is dispatched from the operation itself.
            var operation:AbstractOperation = super.getOperation(methodName);
            Application.application.callLater(operation.dispatchEvent,[ResultEvent.createEvent(response,token,message)]);
            return token;
        }

        public function setResult(methodName:String,responseValue:Object):void {
            _resultDictionary[methodName] = responseValue;
        }

    }
}

Nothing overly swanky, but all the magic happens courtesy of this line :
override flash_proxy function callProperty(name:*, ... args:Array):*

This method gets invoked whenever you call a method on the class which has not been defined in code. We catch the call, and generate an Async token that makes the caller think that we’re busily off chatting to our webserver.

The other key line is this:
Application.application.callLater(operation.dispatchEvent,[ResultEvent.createEvent(response,token,message)]);

In essence, we’re just dispatching a result event here. But, because our method is called syncronously, and webservices behave asyncronously, it’s important that we dispatch the event on the next frame. Hence Application.application.callLater.

Also, the result event must come from the operation itself, not our mock service, so that whoever has called this method gets notified of the result event, just like they would if it were a normal webservice.

So, with all that done, we simply set up the webservice, and invoke it:


var result:XML = new XML();
var ws:MockWebService = new MockWebService();
ws.setResult(”callMyRemoteMethod”,result)
someClass.webservice = ws;

It’s important (and good design practice) that you expose the webservice on your class as property that can be modified at runtime.

That’s pretty much it.

Questions and comments welcomed.

Marty

Although there’s a bunch of cool plugins out there for formatting code, for those of us too cheap to host our own wordpress blog, options are limited.

Luckily, there’s a handy javascript app over on blogger which gives us some clean markup to paste in.

Checkit:

http://formatmysourcecode.blogspot.com/

I’m a fan of unit tests. And, although I probably wouldn’t blazen it across my chest like some, I am sold of the benefits.

However, coming from .NET, I miss quite a bit of the elegance present in NUnit when working with FlexUnit.

Most specifically, the setup of a test suite is kinda clunky.

Normally, you have several classes of unit tests, each which have a static suite() method, returning a test suite comprising the unit tests in that class.

Check out the following example:



 public static function suite():TestSuite {

    	var ts:TestSuite = new TestSuite();	   	ts.addTest( new MyTestClass(”testMethodA”) );

    	ts.addTest( new MyTestClass(”testMethodB”) );

    	ts.addTest( new MyTestClass(”testMethodC”) );

    	ts.addTest( new MyTestClass(”testMethodD”) );

    	return ts;

 }

As you can appreciate, it doesn’t take long for this to get long and clunky. Also, maintanence is a pain in the butt — adding tests don’t get run if you forget to add it in the Suite method, changing names causes RTE, etc etc etc.

In NUnit (and, presumably JUnit), you just decorate a class with [TestFixture], and a method with [Test], and NUnit takes care of the rest using that groovy cat, Reflection.

Luckily for us, Flex gives us the ability to tell the compiler to retain custom metatags in Flex 3. This means we can achieve similar functionailty — at least at the method level.

The first step is to set the compiler option. In Flex Builder 3, right click your project, hop into Flex Compiler, and add this to the list of compiler options:

-keep-as3-metadata+=Test

Then, using flash.utils.describeType() we can find any methods within a class that are decoared with our [Test] method.

The following method examines a class, and returns a TestSuite which contains a test for each decorated method.

        /**

         * Generates a test suite with all the methods in a class decorated with [Test] metadata

         * @param clazz

         * @return

         *

         */

        public static function fromClass(clazz:Class):TestSuite {

            var suite:TestSuite = new TestSuite();

            var testMethodNames : XMLList = describeType(clazz).method.(metadata.(@name==”Test”)).@name

            for each (var node:XML in testMethods) {

                    var methodName:String = node.value()

                    var test:Test = new clazz(methodName);

                    suite.addTest(test);

            }

            return suite;

        }

Personally, I chose to add this to the TestSuite class in FlexUnit, though you may prefer a seperate util class.

Now, getting all the tests for a class is as simple as:

var suite:TestSuite = TestSuite.forClass(myClass);

Much more readable!

Comments welcomed.

Marty

Update : I modified the disvoery method to use the E4X expression suggested by Theo. I must’ve been having a brain-fart at the time, as I’m a huge fan of the E4X syntax. Nice spotting Theo!