Sunday, November 19, 2006

Tracing and logging in Flex

This is another area which is pretty simple and powerful, but still many end up writing their own version.

All you have to do is define a new logging target or use the existing 'TraceTarget' to direct logging statements to it.

var traceTarget:ILoggingTarget = new LogViewerTarget(debugBox);
traceTarget.filters = ["com.adobe.*"];
traceTarget.level = LogEventLevel.DEBUG;
Log.addTarget(traceTarget);

Then, to log use one of the methods in the logger class:

private var logger : ILogger = Log.getLogger("com.adobe.SomeClass");

The logging target class looks like, pass the textarea in constructor if you wish to view the log during development:

use namespace mx_internal;
...
public class LogViewerTarget extends LineFormattedTarget
{
....
public function LogViewerTarget() { super(); }

override mx_internal function internalLog(message:String):void
{ this.logs.text += message + "\n"; }
}

Debugging flex webservices

For debugging webservices, the first tool is obviously http monitors like Fiddler or Ethereal(WireShark). Almost everyone who has developed a webservice knows that. It is also true that these tools works well when your webservice is not hosted locally. There are of course other tricks to make it work. But, when it comes to Adobe flex, the challenge is not over even if you got the SOAP response xml back from server. You have to bind it appropriately to see the results. That is where the top secret *j/k* API is useful.
Use "mx.utils.ObjectUtil.toString(resultEvent.result)" to see the structure of result object and get your binding expression correct. Also, see my upcoming post about tracing.

Cairngorm IResponder Async Flexunit testcase

Didn't find any posts addressing FlexUnit async tests using IResponder.
Here is one method of using async flexunit tests with Cairngorm IResponder which involves modifying the flexunit source code.

TestCase.as
------------
public function addResponder(responder : IResponder, timeout : int, passThroughData : Object = null) : IResponder
{
if (asyncTestHelper == null)
{
asyncTestHelper = new AsyncTestHelper(this, testResult);
}
asyncMethods.push({func: responder.result, timeout: timeout, extraData: passThroughData, failFunc: responder.fault, responder: responder});
return asyncTestHelper;
}

AsyncTestHelper.as
---------------------
import mx.rpc.IResponder;
public class AsyncTestHelper implements IResponder
...

public function result(event : Object) : void
{
var wasReallyAsync : Boolean = timer.running;
timer.stop();
//if we already failed don't do anything
if (shouldFail)
return;
objToPass = event;
if (wasReallyAsync)
{
testResult.continueRun(testCase);
}
}

public function fault(event : Object) : void
{
var wasReallyAsync : Boolean = timer.running;
timer.stop();
//if we already failed don't do anything
if (shouldFail)
return;
objToPass = event;
if (wasReallyAsync)
{
shouldFail = true;
testResult.continueRun(testCase);
}
}

Then, in your test case function, use the result of
'this.addResponder(this, 5000)' when you need to pass an IResponder callback

eg.
myDelegate.runAsyncFunction(param, this.addResponder(this, 5000));
instead of
myDelegate.runAsyncFunction(param, this);

Cairngorm & Webservice

Cairngorm is good, but here is something you have to watch out for if you are using webservices.
If you locate a webservice using 'ServiceLocator' you have to also call 'loadWsdl()' on the webservice before invoking an operation on it. Otherwise, you don't get any errors nor does the webservice call reach the server (obviously, no result either)