Stubbing a Model Dependency

335 views
Skip to first unread message

dougrdotnet

unread,
Sep 23, 2011, 8:39:59 AM9/23/11
to mock...@googlegroups.com
Hello, and thank you.
I am trying to stub out a model in FlexUnit, similar to what stray has done in this example using asunit: https://github.com/Stray/robotlegs-demo-StrategyGame/blob/master/test/strategy/controller/commands/daycycle/ProcessDayEndCommandTest.as

I am receiving an error that appears to be quite generic and would like to see if someone could point me in the right direction to setup this test of a command's execute method when there is a model dependency:

Error
at mockolate.ingredients::InstanceRecipeBuilder/withClassRecipe(InstanceRecipeBuilder.as:21)
at mockolate.ingredients::Mockolatier/nice(Mockolatier.as:152)
at global/mockolate::nice(nice.as:28)
**[ at com.jdrf.controller.constituents::CreateOrUpdateConstituentCommandTest/run(CreateOrUpdateConstituentCommandTest.as:41) ]
at flex.lang.reflect::Method/apply(Method.as:244)
at org.flexunit.runners.model::FrameworkMethod/invokeExplosively(FrameworkMethod.as:201)
at org.flexunit.internals.runners.statements::InvokeMethod/evaluate(InvokeMethod.as:72)
at org.flexunit.internals.runners.statements::SequencerWithDecoration/executeStep(SequencerWithDecoration.as:100)
at org.flexunit.internals.runners.statements::StatementSequencer/handleChildExecuteComplete(StatementSequencer.as:141)
at org.flexunit.token::AsyncTestToken/sendResult(AsyncTestToken.as:107)
at org.flexunit.internals.runners.statements::InvokeMethod/evaluate(InvokeMethod.as:73)
at org.flexunit.internals.runners.statements::SequencerWithDecoration/executeStep(SequencerWithDecoration.as:100)
at org.flexunit.internals.runners.statements::StatementSequencer/handleChildExecuteComplete(StatementSequencer.as:141)
at org.flexunit.internals.runners.statements::StatementSequencer/evaluate(StatementSequencer.as:109)
at org.flexunit.internals.runners.statements::RunBeforesInline/evaluate(RunBeforesInline.as:97)
at org.flexunit.internals.runners.statements::RunAftersInline/evaluate(RunAftersInline.as:104)
at org.flexunit.internals.runners.statements::StackAndFrameManagement/handleTimerComplete(StackAndFrameManagement.as:138)
at flash.events::EventDispatcher/dispatchEventFunction
at flash.events::EventDispatcher/dispatchEvent
at flash.utils::Timer/tick

Here is the related setup code:


<pre>

private var instanceCommand:CreateOrUpdateConstituentCommand;

protected static const CONSTITUENT:Constituent = new Constituent();


[Before(order=1)]

public function setUp():void

{

var mockolateMaker:IEventDispatcher = prepare(IConstituentModel);

mockolateMaker.addEventListener(Event.COMPLETE, prepareCompleteHandler);

}

[Before(order=2)]

public function run():void

{

instanceCommand = new CreateOrUpdateConstituentCommand();

instanceCommand.eventDispatcher = new EventDispatcher();

var constituent:Constituent = CONSTITUENT;

instanceCommand.event = new PetitionEvent ( PetitionEvent.PETITION_SUBMITED, falsefalse, constituent );

instanceCommand = nice(IConstituentModel);

}

protected function prepareCompleteHandler ( event : Event ) : void

{

IEventDispatcher(event.target).removeEventListener(Event.COMPLETE, prepareCompleteHandler);

}

</pre>

And the related test:

<pre>

[Test]

public function testExecute():void {

stub(instanceCommand.constituentModel).setter('constituent').arg(CONSTITUENT);

assertTrue("Execute returns void", (instanceCommand.execute() == void));

}

</pre>

dougrdotnet

unread,
Sep 23, 2011, 10:55:43 PM9/23/11
to mock...@googlegroups.com
I thought I'd add my console output as well as it appears that the model is actually getting generated correctly:

FloxyMockolateFactory prepareClassRecipes [class IConstituentModel],

ProxyRepository.prepareClasses 1 [class IConstituentModel],

ProxyRepository.prepareClasses classToPrepare [class IConstituentModel]

ProxyRepository.prepareClasses namespacesToProxy 

ProxyRepository.prepareClasses proxy mockolate.generated:IConstituentModel6B41B06A6C809987C67C4A48442E27E19F3C0220

[SWF] crypt:MyAppClient:bin-debug:FlexUnitApplication.swf:[[DYNAMIC]]:7 - 1,198 bytes after decompression

ProxyRepository.prepareClasses loaded item [class IConstituentModel],,mockolate.generated:IConstituentModel6B41B06A6C809987C67C4A48442E27E19F3C0220

ProxyRepository.prepareClasses loaded mockolate.generated::IConstituentModel6B41B06A6C809987C67C4A48442E27E19F3C0220

ProxyRepository.prepareClasses loaded [class IConstituentModel] [class IConstituentModel6B41B06A6C809987C67C4A48442E27E19F3C0220]

FloxyMockolateFactory prepareClassRecipes prepared [class IConstituentModel] [class IConstituentModel6B41B06A6C809987C67C4A48442E27E19F3C0220]

FloxyMockolateFactory prepareClassRecipes classRecipe [ClassRecipe classToPrepare=[class IConstituentModel] namespacesToProxy=null proxyClass=null]

FloxyMockolateFactory prepareClassRecipes complete [class IConstituentModel],,mockolate.generated:IConstituentModel6B41B06A6C809987C67C4A48442E27E19F3C0220

Stray

unread,
Sep 24, 2011, 7:07:13 AM9/24/11
to mock...@googlegroups.com
Hi Doug,

I'm not sure if this is a FlexUnit difference - but usually my 'prepareCompleteHandler' would trigger the run(); rather than it being marked with a [Before].

Whether that will make a jot of difference I don't know!

Stray

dougrdotnet

unread,
Sep 24, 2011, 7:59:06 AM9/24/11
to mock...@googlegroups.com
Hi Stray!!

Ya, the setup/run is totally where I am hacking around.  My breakpoints in testExecute() and my command never get hit, even though testExecute() shows as the failed test.  It seems to me that the prepare is working though as the model appears to be generated.  So that leaves me thinking that it might be race condition occurring up in the setup.  In one of my versions I actually saw order=2 get hit prior to order=1, I had the setup and run methods doing the opposite then, with run being order=2.  I switched to this version thinking that FlexUnit might actually be looking for 'setUp()' first, I don't have any information to substantiate this, however, the order of methods run is now correct.  I believe that I saw an attribute for meta somewhere that assigns a delay in milliseconds to allow the prepare time to complete, I am searching around for any docs/examples of that at the moment.  

dougrdotnet

unread,
Sep 24, 2011, 10:27:48 AM9/24/11
to mock...@googlegroups.com
Ah, thanks, I think what you mentioned has me a step closer.  I changed up the code a bit and found that in my run method I was trying to assign instanceCommand = nice(IConstituentModel); which of course gave me a type coercion error.  I then put a call to run() in the eventListener for mackolateMaker's Event.COMPLETE, removing the order meta, and found that the handler is never getting called.  So, I think the question now is centered on mockolateMaker event completion and the handler getting called.  The resulting symptom at this point is testExecute() is failing because instanceCommand is null at this line: stub(instanceCommand.constituentModel).setter('constituent').arg(CONSTITUENT);

[Before]

public function setUp():void

{

var mockolateMaker:IEventDispatcher = prepare(IConstituentModel);

mockolateMaker.addEventListener(Event.COMPLETE, prepareCompleteHandler);

}

public function run():void

{

instanceCommand = new CreateOrUpdateConstituentCommand();

instanceCommand.eventDispatcher = new EventDispatcher();

var constituent:Constituent = CONSTITUENT;

instanceCommand.event = new PetitionEvent ( PetitionEvent.PETITION_SUBMITED, false, false, constituent );

instanceCommand.constituentModel = nice(IConstituentModel);

}

protected function prepareCompleteHandler ( event : Event ) : void

{

run();

IEventDispatcher(event.target).removeEventListener(Event.COMPLETE, prepareCompleteHandler);

}

dougrdotnet

unread,
Sep 24, 2011, 6:05:18 PM9/24/11
to mock...@googlegroups.com
Here is the solution!!

Rather than use prepare, I used a MockolateRule [Rule] and mocked the model using [Mock].  Actually much simpler than what I was attempting to do.  Do let me know if there is a better way to approach this but this seem to be pretty solid setup.

[Rule]

public var rule:MockolateRule = new MockolateRule();

[Mock]

public var constituentModel:IConstituentModel;

private var instanceCommand:CreateOrUpdateConstituentCommand;

protected static const CONSTITUENT:Constituent = new Constituent();

[Before]

public function setUp():void

{

instanceCommand = new CreateOrUpdateConstituentCommand();

instanceCommand.eventDispatcher = new EventDispatcher();

instanceCommand.event = new PetitionEvent ( PetitionEvent.PETITION_SUBMITED, false, false, CONSTITUENT );

instanceCommand.constituentModel = constituentModel;

}

Drew Bourne

unread,
Sep 25, 2011, 8:35:31 PM9/25/11
to mock...@googlegroups.com
For FlexUnit the setup you have above using the MockolateRule is the recommended approach. 

I should be able to make the error you encountered more verbose and specific as it looks like I left out an error message which should have been something like "No proxy class prepared for <[class IConstituentModel]>".

This error would have been happening as the method you marked with [Before(order=1)] is async. Unless you tell FlexUnit a method is async it will run the next [Before] as soon as possible which causes Mockolate to look for a proxy class that is not yet prepared. An example of how to do this is https://gist.github.com/1241369 (imports removed for brevity). 

cheers, 
Drew

dougrdotnet

unread,
Sep 25, 2011, 10:27:58 PM9/25/11
to mock...@googlegroups.com
Hi Drew,

I was looking for something along those lines, in the console output I posted above I had noticed the following lines:

FloxyMockolateFactory prepareClassRecipes classRecipe [ClassRecipe classToPrepare=[class IConstituentModel] namespacesToProxy=null proxyClass=null]

FloxyMockolateFactory prepareClassRecipes complete [class IConstituentModel],,mockolate.generated:IConstituentModel6B41B06A6C809987C67C4A48442E27E19F3C0220

In that first line I saw the namespacesToProxy=null proxyClass=null] and considered if that was a hint, although I didn't have enough information to discern what that meant.  Then, in the second line it indicated that my model had actually been prepared.  Now I understand that it probably had been prepared, but it was late as a result of my setup.

Anyway, I'm really pleased with my entry into Mockolate, this project is the first that I've implemented it.  I figured that it would be a challenge, but like RL, the curve is there but seems to be pretty quick to traverse.  Thanks for this group, its resources like this that help get in and get going.

Doug

Reply all
Reply to author
Forward
0 new messages