Thanks Matt!

Here's a real-world example of where the fixed ordering of the 
addAsync calls just bit me:

I'm testing what is essentially an HTTPService, that could throw a 
result or a fault.  I instinctively wrote the following:

public function testChangeUser():void {
  // cp is my service object that throws results and faults
  var tempfunc:Function = addAsync(handleChangeUserPart1,TIMEOUT);
  cp.faultCallback = addAsync(
    handleUnexpectedFault,
    TIMEOUT,
    "testChangeUserPart1",
    onNotCalledIgnore);
  // NOTE: I had to use a temporary function because I don't expect
  // the fault handler to be called, but the error must be caught if
  // it is
  cp.addUser("userToBeAdded",tempfunc);
}

private function handleChangeUserPart1(data:ResultEvent):void {
  assertEquals("true",[EMAIL PROTECTED]);
  // ok, user has been added, verify that I can change the username
  var tempfunc:Function = addAsync(handleChangeUserPart2,TIMEOUT);
  cp.faultCallback = addAsync(
    handleUnexpectedFault,
    TIMEOUT,
    "testChangeUserPart2",
    onNotCalledIgnore);
  cp.changeUserName("oldname","newname",tempfunc);
}

private function handleChangeUserPart2(data:ResultEvent):void {
  assertEquals("true",[EMAIL PROTECTED]);
}

private function handleUnexpectedFault(e:*,d:*=null):void 
{fail("blah");}
private function onNotCalledIgnore(d:*):void {}

The above seems pretty straightforward.  I add the user, when the 
response comes back and I confirm that the user was added, I change 
the username and then confirm that the username was changed.

However, it doesn't work like that.  Because I have a second call to 
addAsync() in testChangeUser, the Unit Test framework expects that 
the next async callback to come is my fault event, which is not the 
case -- my next event is the receipt of my call to change the 
username.  I don't care if it gets skipped nor do I want to require 
that it gets called.  Thus, my testcase errors out because of 
ordering.

I can't remove the call or reference to addAsync(myFaultCallback) 
because I need it to handle faults....

I haven't been able to come up with a workaround for this case -- 
any suggestions?

Matt, I'll gladly try to help fix these issues, but I need a bit 
more direction on where to look (ok... I could figure it out, but 
I'm not that zealous nor do I have quite that much time ;).

BTW, I have wondered many times if FlexUnit would work better if the 
whole thing was structured on async events.  Of course, that would 
require a major re-work, but it seems a lot more natural given the 
number of async events that need to be dealt with in Flex....

Thanks for the help everyone.

--Kaleb

--- In flexcoders@yahoogroups.com, "Matt Chotin" <[EMAIL PROTECTED]> 
wrote:
>
> Doing a while loop won't work, if it did we wouldn't have all the
> complications of this system :-)  Your idea of #1 is exactly 
right,
> setup now needs to become more like the async calls.
> 
>  
> 
> Sorry, I haven't looked at this code in a year, you'll need to 
muddle
> through but it should be doable.
> 
>  
> 
> Matt
> 
>  
> 
> ________________________________
> 
> From: flexcoders@yahoogroups.com 
[mailto:[EMAIL PROTECTED] On
> Behalf Of kaleb_pederson
> Sent: Tuesday, August 22, 2006 12:19 PM
> To: flexcoders@yahoogroups.com
> Subject: [flexcoders] RE: Asynchronous TestCase.setUp in FlexUnit 
(and
> another use case)
> 
>  
> 
> Matt and all,
> 
> I took a quick stab at this as it didn't look too bad, but 
> unfortunately, it isn't quite that simple. FlexUnit is written 
such 
> that it expects a number of things to happen synchronously, which 
> causes some other problems in this case.
> 
> Let me explain. After modifying TestCase::runMiddle() to wait for 
a 
> flag indicating that the testcase setup has completed, runMiddle 
> fires off a timer and waits for the flag to change. At this point, 
> runMiddle, as called by ProtectedMiddleTestCase::protect(), 
returns 
> and the next TestCase is fired off. In the end, this results in 
the 
> setup function being called many times before the test cases 
> actually fire off (as the test cases are now waiting for the flag 
to 
> change) and many test functions being called in parallel when the 
> flag changes.
> 
> There are a couple of different ways that seem like obvious 
> solutions:
> 
> 1) Change the setup process so that it worked kind of like the 
async 
> calls as handled by addAsync.
> 2) Instead of allowing runMiddle to return (as its synchronous), 
put 
> it in a while loop waiting for the flag to change [!BAD HACK!]
> 
> I don't fully understand the interactions between all the 
different 
> classes and objects at this point, so I'm not sure if there is an 
> easy way to get to a reasonable solution, so I'm asking for 
> feedback. Is there an easier way to make this work correctly? 
> Other suggestions?
> 
> Another sample use case:
> 
> Unfortunately, when callbacks are registered with addAsync(), the 
> order in which the calls are made imposes a restriction on the 
order 
> in which the callbacks can return.
> 
> For example, assume my test requires two different XML files 
loaded 
> from externally:
> 
> public function testValidateExternalRefs():void {
> var loader1:URLLoader = new URLLoader();
> var loader2:URLLoader = new URLLoader();
> loader1.addEventListener(Event.COoverride 
> MPLETE,addAsync(onComplete1,TIMEOUT));
> 
> 
loader2.addEventListener(Event.COMPLETE,addAsync(onComplete2,TIMEOUT));
> 
> loader1.load(new URLRequest(myUrl1));
> loader2.load(new URLRequest(myUrl2));
> }
> 
> The use case above presents a problem because I cannot guarantee 
> which response is going to come back first. Admittedly, in this 
> case I could load the files in the setUp call (or chain a bunch of 
> events so that the first one has loaded, and then the second one 
has 
> loaded, and so on and so forth). The problem that I'm running into 
> is because of the required strict ordering of asynchronous 
> responses, I'm having to chain a lot of events for something that 
> could be quite simple. Although the above use case is fabricated, 
I 
> hope it shows the problem.
> 
> Does anybody have some suggestions on how I might work around 
these 
> issues? I'll gladly modify code if I need to -- I'm just trying to 
> avoid having to understand all the code from the ground up to come 
> up with a solution.
> 
> Thanks for the help.
> 
> --Kaleb
> 
> -----Original Message-----
> From: Matt Chotin [EMAIL PROTECTED]
> Sent: Mon, 06 Mar 2006 22:40:46 -0800
> Subject: [flexcoders] Asynchronous TestCase.setUp in FlexUnit
> 
> My thought is that this is a good use-case and you should look 
into
> proposing how a class should indicate asynchronous setup and 
> teardown
> and then go ahead and implement. Then submit as a proposal :-)
> 
> One idea is that we could add a variable called ready to the 
> TestCase
> that is by default true. We would then adjust the runMiddle() 
> method to
> check the ready variable and if it is true go ahead and call
> runTestOrAsync. If it is false it simply would wait and call 
itself
> again a little later. Then in your setup you set ready to false, 
> and
> when your data loads you set ready to true.
> 
> I haven't thought it all the way through, but something like this 
> could
> work. Check the source out and maybe override some of those 
methods 
> in
> your own testcase to see how it works out.
> 
> Matt
> 
> -----Original Message-----
> From: bringrags [EMAIL PROTECTED]
> Sent: Monday, March 06, 2006 2:02 PM
> Subject: [flexcoders] Asynchronous TestCase.setUp in FlexUnit
> 
> Hi,
> 
> I've been using FlexUnit with one of my projects and ran into a
> problem. In one of my test cases, I want to load a bunch of data 
> from
> an XML file in the TestCase.setUp() method, and have all of the
> individual tests use this as a fixture.
> 
> The problem is that loading a file is an asynchronous operation, 
but
> there's no mechanism to make setUp asynchronous. Consider the
> following excerpt:
> 
> public function setUp():void
> {
> var loader:URLLoader = new URLLoader();
> loader.addEventListener(Event.COMPLETE,onComplete);
> loader.load(new URLRequest("myfile.xml"));
> }
> 
> private function onComplete(event:Event):void
> {
> var loader:URLLoader = URLLoader(event.target);
> myXML = new XML(loader.data);
> }
> 
> public function testSomething():void
> {
> assertTrue("Should pass", myXML.someElement = "some value");
> }
> 
> The problem is that testSomething() gets called before 
onComplete(). 
> Ideally I would like to prevent the tests from running until the
> onComplete() method is called.
> 
> FlexUnit provides support for having a chain of asynchronous 
tests,
> but it doesn't seem to provide support for chaining asynchronous 
> setup
> tasks. One possible workaround is to have each test method 
> explicitly
> prepare the setup fixture:
> 
> public function testSomething():void
> {
> beginTestSetup(testSomethingHandler);
> }
> 
> private function testSomethingHandler(event:Event):void
> {
> endTestSetup(event);
> 
> assertTrue("Should pass", xml.someElement = "some value");
> }
> 
> private function beginTestSetup(eventHandler:Function):void
> {
> var loader:URLLoader = new URLLoader();
> 
> 
loader.addEventListener(Event.COMPLETE,addAsync(eventHandler,1000));
> loader.load(new URLRequest("myfile.xml"));
> }
> 
> private function endTestSetup(event:Event):void
> {
> var loader:URLLoader = URLLoader(event.target);
> myXML = new XML(loader.data);
> }
> 
> But this is less than ideal. Any thoughts?
> 
> -- Brian
>





--
Flexcoders Mailing List
FAQ: http://groups.yahoo.com/group/flexcoders/files/flexcodersFAQ.txt
Search Archives: http://www.mail-archive.com/flexcoders%40yahoogroups.com 
Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/flexcoders/

<*> To unsubscribe from this group, send an email to:
    [EMAIL PROTECTED]

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/
 


Reply via email to