FlashCamp Orlando 2009 Early Bird Extended!

Brian LeGros | May 11th, 2009 | news  

The early bird price (~$35) for registration to FlashCamp Orlando 2009 has been extended until May 15, 2009! Let’s face it, in this economy, every little bit helps. If you weren’t able to make it out to 360|Flex or cf.objective this year, or you can spare a Friday out of the office, come out to support a local developer event sponsored by Adobe and Universal Mind. Lunch, parking, door prizes, great sessions, and lots of great networking opportunities come with the registration price. The best part of it all is at the end of the day, you can drive home instead of staying in a dank motel like you do with most events. Tampa and Melbourne are still what I consider within driving distance, but you may still elect for the motel/hotel.

If you haven’t seen it yet, an interview has been posted with Adogo’s very own Jason Madsen about his session at FlashCamp. Hope you can make it out!

FlexUnit 4 public alpha now available

Brian LeGros | May 4th, 2009 | news  

Just a quick note. Last night the Mike did a blog post on the new features coming to FlexUnit and the working title of FlexUnit 4 for the project. You can find the blog post @ http://blogs.digitalprimates.net/codeSlinger/index.cfm/2009/5/3/FlexUnit-4-in-360-seconds. There is a link to the alpha in the post and as soon as it’s available on Adobe’s servers, we’ll publish that URL as well. Keep in mind that it does support legacy FlexUnit and Fluint tests, so dig in and let us know what you think!

FlashCamp Orlando 2009 Registration Open

Brian LeGros | May 3rd, 2009 | news  

A little belated, but registration for FlashCamp Orlando 2009 opened this weekend with early bird expiring on May 1st at $35. Fear not though, the standard registration price is a mere ~$50 which, IMO, is a significantly small fee to attend a one day event.

FlashCamp (formerly FlexCamp) is a one-event day sponsored by Universal Mind and Adobe in which developers and designers can take a deep dive into topics ranging from introductory to advanced from the Flex world. This year Adogo’s very own Maxim Porges and Jason Madsen will be presenting along side Greg Wilson, of Adobe, as well as David Tucker, Andrew Powell, and Christian Saylor, of Universal Mind, and Carl Smith from nGenWorks. The event will take place on May 29th from 8:30 AM to 5:30 PM. Registration includes free parking, lunch, door prizes and lots of great networking.

If you have the time available, I definitely suggest signing up for a spot, availability is limited. I won’t be able to attend, or speak at, the event since we’ll be welcoming our 1st child into the world this month, but I would definitely be there otherwise. Hope you can make it out!

New FlexUnit … what?

Brian LeGros | May 3rd, 2009 | news  

Mike Labriola today announced on the Fluint Discussion group the big news a few in the Fluint team have been sitting for months now. The Fluint team is leading an OSS initiative to create the next version of the FlexUnit product. What’s great about this initiative (as Mike outlines on the mailing list) is that the new version of Fluint has been designed to mimic a lot of the conventions found in JUnit 4 while still addressing all of the problems Fluint solves for us in the Flex world. I know, for me, this means being more productive when writing tests and finally having better tooling when working with Flex. Here are some of the features listed from Mike’s email:

  • Metadata based Test and Suite identification (no more need to extend testcase or testsuite)
  • Hamcrest matchers courtesy of the hamcrest-as3 project.
  • Theories, DataPoints and Assumptions
  • Ignorable tests
  • Enhanced Sorting and Filtering
  • Custom runner integration

Probably one of the coolest part of this entire framework thus far is that last item. The Fluint team has already been able to successfully run legacy unit tests from the current versions of FlexUnit and Fluint. This means that you can have hybrid suites of tests in the new FlexUnit (e.g. -FlexUnit, Fluint, FUnit, asunit, etc) making migration between frameworks relatively simple.

We’re going to be launching a public alpha release in the near future, but we are still continuing work on Fluint at least as far as release 1.2 (1.1.1 was release yesterday). Please keep in mind however, the goal is for FlexUnit to become what would have been Fluint 2.0. Look for more details in the coming weeks.

Here’s to better testing!

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.

Code and slides finally posted from FlexCamp Miami

Brian LeGros | March 29th, 2009 | conferences  

Sorry to everyone who’s been asking about a copy of my presentation from FlexCamp Miami. I’ve just posted the source and slides for my presentation @ http://svn.adogo.us/200903-FlexCampMiami/ along with Max, who had his stuff up pretty quickly after the conference. I wanted to take some time to add a better example of an integration test which is now available in the RestaurantGrid component project. What delayed me was finding an easy way to explain how to test the DataGrid embedded within the RestaurantGrid; I tried to provide the most basic of examples with and without the help of the Flex Automation API.

Hope this helps those who were interested; sorry again about the delay. If you have any questions, please don’t hesitate to contact me via comments or email me @ me at brianlegros dot com. Also, if you find yourself in the Orlando area, always feel free to drop by an Adogo meeting. This month we’ve got a great JavaScript topic being presented by Adam as well as Max giving his FlexCamp Miami presentation with, if we’re lucky, working AOP in AS3 via Loom! Check out the Adogo blog for more information on time and location. Hope you can make it!

FlexCamp Miami Wrap-up

Brian LeGros | March 6th, 2009 | conferences  

For a one day event, FlexCamp Miami had tons of information packed into its 8 sessions. Greg Wilson started us out with a great intro to some of the new features coming in Gumbo (Flex 4) followed by David Tucker digging down into the persistence side of AIR, along with some new 1.5 features. After the break, Max blew away the crowd with loom and some AS3 internals followed by Andrew Powell and some awesome examples of using Merapi to bring some deeper OS interaction to AIR. We broke for lunch and then Christian Saylor gave a really motivating presentation on the importance of UX for developers. I had to follow him with my CI presentation, which didn’t even compare and ran long, but then Jeremy Grelle swooped back in and kept everyone’s attention with Milestone 2 of the new Spring/BlazeDS integration (released this last Wednesday). Laura Arguello finished out the day with a cool introduction to Mate. Universal Mind did a great job with the event, lunch was good, and my brain is full.

I should have my code available on the Adogo SVN server this week, I’d just like to add an integration testing example before I commit it. Look for Max and my code/presentations there soon. Hopefully we can convince UM to have another one of these a little further North … say Orlando? I think I know a few Central Florida user groups that could help promote it.

NOTE: If you ever make your way down to Coral Gables, give Titanic Restaurant and Brewery a try. They’ve got some really tasty microbrews and even more delicious food. I recommend the Captain Smith’s Rye Ale, super great. For food, I had the Shrimp Po-boy which came with 6 huge tailed shrimp and a nice remoulade. Thanks to Greg for the great meal!

FlexCamp Miami Tomorrow

Brian LeGros | March 5th, 2009 | conferences  

FlexCamp Miami is tomorrow, 03/06/09. If you find yourself without something to do tomorrow, jump in the car and join us in the Hurricane Room at the Bank United Center on the UM Campus. We’ll be starting around 8:00 AM and should finish up around 5:00 PM; lunch is included. If you’d like to attend, just hop over to their EventBrite page and register. We’ve got some great speakers including Greg Wilson, David Tucker, Andrew Powell, Laura Arguello, Christian Saylor, Jeremy Grelle, along with Max and myself from the Adogo.

Hope you can make it!

Using Stubs for HTTPService and RemoteObject in Flex

Brian LeGros | February 21st, 2009 | programming  

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
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;
 
   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;
 
      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
      {
         var token : AsyncToken = new AsyncToken(null);
         var service : HTTPService  = this;
 
         //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, 
            function(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 = isFaultCall(parameters) ? responder.fault : responder.result;
                  response.apply(null, [generateEvent(parameters)]);
               }
 
               //dispatch event to service just in case token wasn't used
               service.dispatchEvent(generateEvent(parameters));
            }, 
            false, 
            0, 
            true
         );
 
         timer.start();
 
         return token;
      }
 
      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.remoting.RemoteObject;
   import mx.rpc.Fault;
 
   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;
 
   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
   {
      var token : AsyncToken = new AsyncToken(null);
      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, 
         function(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
            stub.dispatchEvent(generateEvent(args));
         }, 
         false, 
         0, 
         true
      );
 
      timer.start();
 
      return token;
   }
 
   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()]);
      }
   }
}

Banzai Sushi and Thai Restaurant – Melbourne, FL

Brian LeGros | February 20th, 2009 | food  

Today my wife and I walked away from dinner saying, “That was the best meal we’ve had in a long time.” We’ve been going to Banzai Sushi and Thai Restaurant since the first week we moved into Brevard county. A friend of mine, who had grown up in Melbourne, recommended it as one of his favorite Japanese and Thai restaurants in the area. Ever since that first visit we have never had a bad experience being spoiled with amazing food, service, and ambiance. To call Banzai just an eatery doesn’t do it justice, it’s a dining experience. In fact Banzai has kept up its dining traditions when most restaurateurs have been quick to abandon them in these tough economic times. Allow me to share our latest experience.

Upon arriving at their small, but comfortable location, you are immediately greeted by one of the servers and immediately seated at a table; we’ve never had to wait. Within a minute or so, your server arrives with hot towels to clean your hands and small salad bowls with tiny spoons. The salad is a mixture of diced tomatoes and cucumber, shredded carrots, mandarin oranges, and pieces of fried tempura batter. It’s a great balance of sweet and salty and perfect to wet your appetite. We usually like to start with a pot of hot green tea ($1.50 p/person) and a couple ice waters. Once we work our way through the massive list of sushi, Japanese, Thai, and Chinese selections, we’ve never had to wait more than a 10-15 minutes to start our meal. This time around, I ordered one of the most fragrant and tasty green curry dishes with chicken (~$10) and my wife ordered the small green salad (~$3) and the shrimp and vegetable tempura appetizer (~$8). The curry is prepared with coconut millk, bell pepper, bamboo shoots, fresh basil, and red pepper oil in a huge portion; if you like spicy, try the Thai hot for that good kind of spicy. The small green salad comes with your option of ginger or honey ginger dressing on top of iceberg and romaine lettuce, tomato, shredded carrots, and sliced cucumber. The tempura appetizer is big enough to be a meal for a single person coming with three shrimp, onion, broccoli, and sweet potato. If all of this food wasn’t enough, at the end of the meal, the server brings out fried sweet doughnuts, dusted with sugar granules. This time around we didn’t order any sushi, but I have to say that Banzai has some of the best quality sushi for your dollar. Their sushi chefs will make pretty much anything you’d like, even if it’s not on the menu. The rolls are packed full of ingredients and they even have surfboards for larger groups.

Adding to the experience of dining at Banzai, every server in the restaurant is your server. They are all equally friendly and courteous offering help to anyone who needs it. I’m not sure if he’s the manager or owner, but even the man in charge is out and about taking care of his customers, making it a pleasent evening for everyone in the restaurant. What’s probably the best part of the service however, is the facet most people don’t consider, invisibility. Banzai works like a well oiled machine providing its customers with whatever they need, but without them having to ask for it. This breeds the peaceful quiet that I have to believe all of Banzai’s patrons associate with the restaurant.

Banzai Sushi and Thai Restaurant provides a high quality experience for what has become a more reasonable price now-a-days. The quality of food is high and you’ll find yourself eager for your next visit before you even walk out of the door. If you’re looking for an establishment that is just as much about the time you spend there as it is the food, do yourself a favor and give Banzai and shot. I promise you won’t regret it.

Banzai Sushi and Thai Restaurant is located in the Publix plaza on the corner of Lake Washington and Wickham at 3208 Lake Washington Road, Melbourne, FL.