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/