flexRpcStubs 0.3 released

Brian LeGros | April 10th, 2010 | news, programming  

I’ve pushed out a couple new features and a bug fix for the flexRpcStubs project. Release 0.3 of the library is available for download on github. In terms of features, you can now filter HTTP calls by HTTP method as well as parameters and HTTP headers. Arguments provided to the result/fault method of HTTPServiceStub and RemoteObjectStub can now be of type literal, Class, Date, RegExp, or Hamcrest matcher rather than just literals and Hamcrest matchers; thanks to Drew for letting me steal the idea from Mockolate, my new favorite mock object framework for AS3. I also fixed a bug in RemoteObjectStub which was not dispatching events on the RemoteOperationStub; thanks to ropp for the fix.

If anyone has SDK classes they’d like to see stubs for, please let me know. I’ve been sent a draft of a ModuleLoaderStub and have a couple ideas for handling SWFLoader, so keep an eye out for more updates as I find time.

flexRpcStubs version 0.2 released

Brian LeGros | March 1st, 2010 | programming  

I burned the midnight oil tonight and was able to get release 0.2 of the flexRpcStubs project out on Github. In this release I’ve added the ability to add a rootCause to a fault on RemoteObjectStub, the ability to match parameters and headers on HTTPServiceStub, and the ability to use hamcrest-as3 matchers along with literals for both HTTPServiceStub and RemoteObjectStub. Additionally, I’ve thrown up some concise examples which, I hope, will help to show simple use cases using stubs in your unit tests. Here are links to the examples for HTTPServiceStub and RemoteObjectStub, just in case you don’t want to dig in. As always I look forward to feedback on the project. If you don’t want to build it yourself, I’ve thrown out a SWC for download on GitHub as well.

Stubs for mx.rpc classes moved to GitHub

Brian LeGros | February 9th, 2010 | programming  

A short note. For simplicities sake, I’ve created a project on GitHub (http://github.com/blegros/flexRpcStubs) to house the mx.rpc stubs which help with testing Flex service classes. The HTTPServiceStub and RemoteObjectStub classes have had a couple of bugs fixes and I’ve added build script to generate a SWC for simplicity. You can read more about the stubs in my initial posting; I hope to update the project soon with some practical usage examples.

If you have any suggestions for changes, feel free to fork and pass a pull request my way. Hope this helps those who asked for a bit more structure.

Fluint 1.1.1 ready to be released

Brian LeGros | April 29th, 2009 | programming  

After a busy couple of months, I’ve finally gotten off of my ass and decided to do the integration for Fluint 1.1.1 and created the new branch for Fluint 1.2. We’re in the process of getting the artifacts into Google Code, but the release tag is in Subversion now for those who are interested. In this release we had a couple small fixes:

  • Issue #34 – Assets are not located in net/digitalprimates/fluint folder
  • Issue #35 – Can’t find TestResponder
  • Issue #37 – Air Test Runner needs better error handling
  • Added new target to ant build for building the airtestrunner as an .airi file (target => “airtestrunner-intermediary”)
  • Added flex builder metadata files to the samples project

I’ve already added my stubs for HTTPService and RemoteObject to the 1.2 branch for those who want to play around with them. Matt Hughes’ sequence improvements will also be included in 1.2 once I figure out where they ended up. For 1.2 I’m hoping to add some documentation for the wiki to address some really early issues as well as #28. In terms of bug fixes and new features, I’m hoping to tackle issues 32, 38, 41, 42, 44, 45, and 46 (#44 being the highest priority).

With a new baby coming in May, I’m unsure of my schedule, but I’m gonna do my best to get what I can ready (=who knows). In the mean time, kick the tires for us and let us know if there are any issues with 1.1.1.

Using Stubs for HTTPService and RemoteObject in Flex

Brian LeGros | February 21st, 2009 | programming  

UPDATE: I’ve finally created a project for these stubs on GitHub @ http://github.com/blegros/flexRpcStubs. Please consider this code more up to date then what follows below.

Recently I’ve been working on producing stub versions of HTTPService and RemoteObject for some integration tests I’m writing. If you haven’t worked with the concept of a stub before, think of a stub a re-implementation of an object created to produced canned answers to calls made to it during a test (borrowed from Mocks aren’t Stubs). A stub is intended to be purposefully ignorant to everything but what is being asked of it in a test. If you’re familiar with the concept of a mock object, a stub can be considered a specialization of a mock object that has no expectations to manage rather only return values. In a lot of circles the term mock and stub are used interchangeably, but I think the difference is important to note. If you’re interested more in the subject, come and see my presentation at FlexCamp Miami on March 6th, 2009.

Typically, in the case of integration testing, stubs are used to impersonate objects which have direct contact with resources external to your application, or component. In the context of most programming langauges I’ve worked with, these are typically classes built into extension libraries for the language (e.g. – JDBC, log4j, javax.mail, etc). In the context of Flex, services are the primary sets of classes that we end up wishing we could stub out. Unfortunately, the need to stub these types of classes can introduce some complexities, especially without a good mock object framework, because very rarely are the interfaces to these classes simple enough for a developer to impersonate on the fly (i.e. – inline in a single test). In the Java world, frameworks like Spring will create helper objects for testing to supplement these needs (e.g. – MockHttpSession and AbstractTransactionalJUnit4SpringContextTests).

In Flex, I haven’t really found a great set implementations for stubs yet, so this weekend I threw together a first draft of working stub classes for HTTPService and RemoteObject in AS3 using the Flex SDK 3.2. I’ve been using variants of these for my testing and so far, so good. Anyone interested in stubbing WebService, can proabably create a similar model to what I’ve done in RemoteObjectStub and be successful. Each stub is type-safe and adds the following properties for configuration to their base classes:

  • delay : Number – Default: 1000 – Number of milliseconds to delay calling registered responders and dispatch the appropriate events for the stub.
  • result : Function – The method used to map result, or fault, objects to specific signatures of send (for HTTPService) or a method name (for RemoteObject). If passed an object deriving from type mx.rpc.Fault, a mx.rpc.events.FaultEvent will be dispatched rather than a mx.rpc.events.ResultEvent.
  • fault : Function – A sugar method that will take in a faultCode, faultString, and faultDetail to create a mx.rpc.Fault and delegate to result().

Each class also supports the dispatching of the appropriate events to mx.rpc.AsyncToken objects as well as the stub instances themselves, just like their base classes. Here is a example of using HTTPServiceStub, in place of HTTPService, in a test case written using fluint:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ClassWithHTTPServiceDependencyTest extends TestCase
{
   private var _classBeingTested : ClassWithHTTPServiceDependency;
   private var _stub : HTTPServiceStub;
 
   override protected function setUp() : void
   {
      _classBeingTested = new ClassWithHTTPServiceDependency();
      _stub = new HTTPServiceStub("http://thisisntarealdomain.com");
      _stub.delay = 500;
      _classBeingTested.service = _stub;
   }
 
   public function testSendWithTokenResult() : void
   {
      var result : Function = function (event : DynamicEvent, passThroughData : Object) : void
      {
         assertEquals("GOAL!", event.payload);
      };
 
      _stub.result(null, "GOAL!");
 
      _classBeingTested.addEventListener("success", asyncHandler(result, 2000));
      _classBeingTested.someMethodUsingHTTPService();
   }
}

In the above example, the behavior being tested is that when a ResultEvent is dispatched to ClassWithHTTPServiceDependency, it dispatches its own mx.events.DynamicEvent with a reference to the result property of the ResultEvent in its payload property. Please note, the call to send() is being made inside of someMethodUsingHTTPService() but could really be made anywhere inside of the object, we don’t care since the stub can impersonate HTTPService.

The implementations for the HTTPServiceStub and RemoteObjectStub are something I hope to get feedback on and maybe get included in fluint or mock-as3, although I’m sure Drew can think of sexier implementations. Below is the source for anyone who is interested in giving them a go to see if they can help your testing process. I have a few unit tests for each as well, so if anyone’s interested, just let me know and I’ll post that code as well.

Happy coding and here’s to these not working and failing you miserably …

HTTPServiceStub.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package net.digitalprimates.fluint.stubs
{
   import flash.events.TimerEvent;
   import flash.utils.Dictionary;
   import flash.utils.Timer;
 
   import mx.rpc.AsyncToken;
   import mx.rpc.Fault;
   import mx.rpc.IResponder;
   import mx.rpc.events.AbstractEvent;
   import mx.rpc.events.FaultEvent;
   import mx.rpc.events.ResultEvent;
   import mx.rpc.http.HTTPService;
 
   /**
    * Idea borrowed from Sonke Rohde @ http://soenkerohde.com/2008/10/conditional-compilation-to-mock-with-swiz/
    **/
   public class HTTPServiceStub extends HTTPService
   {
      private var _resultData : Dictionary;
 
      //default num of milliseconds to wait before dispatching events
      //don't put too low otherwise your token responders may not be registered
      public var delay : Number = 1000;
 
      private var token : AsyncToken;
      private var parameters : Object;
 
      public function HTTPServiceStub(rootURL : String = null, destination : String = null)
      {
         super(rootURL, destination);
         _resultData = new Dictionary();
      }
 
      public function result(parameters : Object, data : *) : void
      {
         _resultData[parameters] = data;
      }
 
      public function fault(parameters : Object, code : String, string : String, detail : String) : void
      {
         var fault : Fault = new Fault(code, string, detail);
         this.result(parameters, fault);
      }
 
      override public function send(parameters : Object = null) : AsyncToken
      {
         return configureResponseTimer(parameters);
      }
 
      private function configureResponseTimer(parameters : Object) : AsyncToken
      {
         token = new AsyncToken(null);
         this.parameters = parameters;
 
         //use a time to give time for the caller to map responders to the asyncToken
         var timer : Timer = new Timer(this.delay, 1);
         timer.addEventListener(TimerEvent.TIMER_COMPLETE, handleTimer);
 
         timer.start();
 
         return token;
      }
 
      private function handleTimer(event : TimerEvent) : void
      {
         //clean-up
         event.target.removeEventListener(TimerEvent.TIMER_COMPLETE, handleTimer);
 
         //loop over all responders to emulate a successful call being made
         for each(var responder : IResponder in token.responders)
         {
           var response : Function = isFaultCall(parameters) ? responder.fault : responder.result;
           response.apply(null, [generateEvent(parameters)]);
         }
 
         //dispatch event to service just in case token wasn't used
         dispatchEvent(generateEvent(parameters));
      }
 
      private function isFaultCall(parameters : Object) : Boolean
      {
         return (_resultData[parameters] is Fault);
      }
 
      private function generateEvent(parameters : Object) : AbstractEvent
      {
         if(isFaultCall(parameters))
         {
            return new FaultEvent(FaultEvent.FAULT, false, true, _resultData[parameters]);
         }
         else
         {
            return new ResultEvent(ResultEvent.RESULT, false, true, _resultData[parameters]);
         }
      }
   }
}

RemoteObjectStub.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package net.digitalprimates.fluint.stubs
{
   import flash.utils.Dictionary;
 
   import mx.rpc.AbstractOperation;
   import mx.rpc.Fault;
   import mx.rpc.remoting.RemoteObject;
 
   public dynamic class RemoteObjectStub extends RemoteObject
   {
      private var _resultData : Dictionary;
 
      //default num of milliseconds to wait before dispatching events
      //don't put too low otherwise your token responders may not be registered
      public var delay : Number = 1000;
 
      public function RemoteObjectStub(destination : String = null)
      {
         super(destination);
         _resultData = new Dictionary();
      }
 
      public function result(methodName : String, args : Array,  data : *) : void
      {
         if(!methodName || methodName.length == 0)
         {
            throw new Error("Cannot use null or empty method names in RemoteObjectStub.");
         }
 
         if(!args)
         {
            args = [];
         }
 
         if(!_resultData[methodName])
         {
            _resultData[methodName] = new Dictionary();
         }
 
         _resultData[methodName][args.toString()] = data;
      }
 
      public function fault(methodName : String, args : Array, code : String, string : String, detail : String) : void
      {
         var fault : Fault = new Fault(code, string, detail);
         this.result(methodName, args, fault);
      }
 
      override public function getOperation(name : String) : AbstractOperation
      {
         return new OperationStub(this, name, _resultData[name]);
      }
   }
}
 
import mx.rpc.AsyncToken;
import net.digitalprimates.fluint.stubs.RemoteObjectStub;
import mx.messaging.config.ServerConfig;
import mx.rpc.Fault;
import flash.utils.Dictionary;
import mx.rpc.remoting.Operation;
import mx.rpc.remoting.RemoteObject;
import flash.events.TimerEvent;
import mx.rpc.events.AbstractEvent;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import flash.utils.Timer;
import mx.rpc.IResponder;
 
internal class OperationStub extends Operation
{
   public var _resultData : Dictionary;
 
   private var token : AsyncToken;
   private var args : Array;
 
   public function OperationStub(remoteObject : RemoteObject, name : String, resultData : Dictionary)
   {
      super(remoteObject, name);
      _resultData = resultData;
   }
 
   override public function send(... args:Array) : AsyncToken
   {
      return configureResponseTimer(args);
   }
 
   private function configureResponseTimer(args : Array) : AsyncToken
   {
      token = new AsyncToken(null);
      this.args = args;
 
      var stub : RemoteObjectStub = RemoteObjectStub(service);
 
      //use a time to give time for the caller to map responders to the asyncToken
      var timer : Timer = new Timer(stub.delay, 1);
      timer.addEventListener(TimerEvent.TIMER_COMPLETE, handleTimer);
 
      timer.start();
 
      return token;
   }
 
   private function handleTimer(event : TimerEvent) : void
   {
      //loop over all responders to emulate a successful call being made
      for each(var responder : IResponder in token.responders)
      {
         var response : Function = isFault(args) ? responder.fault : responder.result;
         response.apply(null, [generateEvent(args)]);
      }
 
      //send the result event to the RemoteObject as well
      service.dispatchEvent(generateEvent(args));
   }
 
   private function isFault(args : Array) : Boolean
   {
      return (_resultData[args.toString()] is Fault);
   }
 
   private function generateEvent(args : Array) : AbstractEvent
   {
      if(isFault(args))
      {
         return new FaultEvent(FaultEvent.FAULT, false, true, _resultData[args.toString()]);
      }
      else
      {
         var result : * = _resultData[args.toString()];
         return new ResultEvent(ResultEvent.RESULT, false, true, _resultData[args.toString()]);
      }
   }
}

UPDATE: – Thanks to Joel Hooks for exercising these a bit more and figuring out a GC issue with the timer that provided some flukely behavior. The above code now supports his fixes in both HTTPServiceStub and RemoteObjectStub. I’ve also run my unit tests against the latest Flex 4 beta and everything passed. Looks like these may be more useful as we start to use Flex 4.

Mock objects and AS3 : Now I really don’t want to use explicit typing

Brian LeGros | October 25th, 2008 | programming  

So in my search for mock object libraries, I continue to run into frustration with explicit typing in ActionScript 3. I did some searching and found a really great mock object library called mock-as3. It’s an expectation based library, in its early stages, but surprisingly featured and intuitive. Here are some usage examples from the author.

I’ve been writing code in ActionScript using explicit types, like most everyone I know who uses AS3, so mock-as3 out of the box won’t meet my needs. If I wanted to begin using interface classes and stubbing out my mocks (as mentioned in the examples) I could, but I won’t; the author even comments that it is extremely tedious to do and doesn’t necessarily advocate it. He hopes to have features in future versions of the library available to handle this but for now they are not available. In general, implementing interfaces for all classes that I’d like to mock is something I don’t agree with in any language. I’m a believer that refactoring your code will make a use case for the use of a programmatic interface over time; there are explicit cases where they are useful, but in the case of mocking, I’m not a big fan.

In any case, I did some thinking and wondered if there was a way to convert an object to a different type at runtime. I figured it’d take some bytecode manipulation, but I’m new to the game, so others much have thought about this already I assumed. Sure enough, I found an implementation by Darron Schall called ObjectTranslator which will convert an object’s type at run-time. I ran through some basic examples and everything worked as expected, so I thought, why not try to convert Mock, which is the class used to mock an object, to the class type passed in at instantiation? The implementation of ObjectTranslator just switches a byte for the new class type and directly copies the bytes of the object into a new byte stream. Worth a shot right?

In mock-as3′s implementation Mock is a subclass of everyone’s favorite class, Proxy. I did a basic test creating an expectation with the same name as the method in my class I wanted to mock and then used ObjectTranslator to convert the mock’s type. I then passed the typed mock to something to consume it and test to see if my expectations return value was given. Below is a the code I wrote:

1
2
3
4
5
6
7
8
9
10
11
var mock : Mock = new Mock(new MyClass());
trace(describeType(mock));
 
mock.method("method1").returns("PASS!");
trace(mock.method1());
 
var newMock : MyClass = ObjectTranslator.objectToInstance(mock, MyClass);
trace(describeType(newMock));
 
var typedUsage : UsageClass = new UsageClass(newMock);
trace(typedUsage.method1() == "PASS!");

Everything works except the final call to trace() which shows false because the value being returned is “FAIL!”, which is the default value for the method in the class declaration. I thought, well maybe I can add functionality to Mock where on each call to method() or property() I will create a property on the mock with the same name of the property passed in and point it to callProperty or getProperty from Proxy. Mock is declared dynamic after all. I gave it a whirl but no luck, I’m guessing there is something special done with Proxy that when I used ObjectTranslator, didn’t come over. There were also some properties used by Mock that didn’t come over because they were not part of the new type, specifically expectations. Since mock-as3 uses its internal reference to expectations I was hoping I would get this for free, but it didn’t work out from what I can tell. Without a way to eval() the code necessary to create a method signature matching the existing signature in the class declaration, I’m pretty much stumped.

If anyone has any suggestions, I’m all for it, but I kinda threw up my hands and called it a day. The more I play with ActionScript 3, the more it feels like the Flex community is going to have to produce things equivalent to CGLib to do anything flexible with ActionScript3 that is still type-safe (e.g. – mocks, AOP, etc). It sounds like from a thread on FlexCoders that the community really wants a Proxy#newProxyInstance method, so hopefully this will make Proxy a little more useful. I’m not sure, however, if they want to be able to instantiate Proxy at run-time or be able to instantiate a formal target property from Proxy of the target’s type. I’m hoping for the latter, but I’m still new to AS3, so who knows. Back to stubs …