[Inject]
public var event:UserEvent;
override public function execute():void
{
if ( event.usersCollection ) {
if ( !event.usersCollection.length ) {
eventDispatcher.dispatchEvent ( new ViewEvent ( ViewEvent.SET_VIEW_STATE, false, false, StateConstants.NEW_USER ) );
} else if ( event.usersCollection.length ) {
eventDispatcher.dispatchEvent ( new ViewEvent ( ViewEvent.SET_VIEW_STATE, false, false, StateConstants.SELECT_USER ) );
}
}
}
I am testing the individual conditions of the command. Here is my setup:
[Rule]
public var rule:MockolateRule = new MockolateRule();
[Mock]
public var instanceEvent:UserEvent;
private var instanceCommand:ViewStateDecisionCommand;
private var collection:ArrayCollection;
[Before]
public function setUp():void
{
collection = new ArrayCollection();
instanceCommand = new ViewStateDecisionCommand();
instanceCommand.eventDispatcher = new EventDispatcher();
}
[After]
public function tearDown():void
{
instanceCommand = null;
}
I don't even make it into my test method before I get the following runtime exception (I've highlighted the actual error below, Line 40 is actually the event's call to super(type, bubbles, cancelable);):
[SWF] FlexUnitApplication.swf - 3,994,601 bytes after decompression
FloxyMockolateFactory prepareClassRecipes [class UserEvent],
ProxyRepository.prepareClasses 1 [class UserEvent],
ProxyRepository.prepareClasses classToPrepare [class UserEvent]
ProxyRepository.prepareClasses namespacesToProxy
ProxyRepository.prepareClasses proxy mockolate.generated:UserEventD88B6B79B0FD8F435ED6E256A55B83AFEBF5F500
ProxyGenerator.addSuperClassMembers dynamicClass addSuper UserEventD88B6B79B0FD8F435ED6E256A55B83AFEBF5F500
ProxyGenerator.addSuperClassMembers superClass UserEvent
ProxyGenerator.addSuperClassMembers method clone true
ProxyGenerator.addSuperClassMembers property usersCollection true -1
ProxyGenerator.addSuperClassMembers property faultMessage true -1
ProxyGenerator.addSuperClassMembers superClass Event
ProxyGenerator.addSuperClassMembers method stopPropagation true
ProxyGenerator.addSuperClassMembers method stopImmediatePropagation true
ProxyGenerator.addSuperClassMembers method preventDefault true
ProxyGenerator.addSuperClassMembers method isDefaultPrevented true
ProxyGenerator.addSuperClassMembers method formatToString true
ProxyGenerator.addSuperClassMembers method toString true
ProxyGenerator.addSuperClassMembers method clone false
ProxyGenerator.addSuperClassMembers property currentTarget true -1
ProxyGenerator.addSuperClassMembers property eventPhase true -1
ProxyGenerator.addSuperClassMembers property type true -1
ProxyGenerator.addSuperClassMembers property bubbles true -1
ProxyGenerator.addSuperClassMembers property cancelable true -1
ProxyGenerator.addSuperClassMembers property target true -1
[SWF] FlexUnitApplication.swf/[[DYNAMIC]]/1 - 5,344 bytes after decompression
ProxyRepository.prepareClasses loaded item [class UserEvent],,mockolate.generated:UserEventD88B6B79B0FD8F435ED6E256A55B83AFEBF5F500
ProxyRepository.prepareClasses loaded mockolate.generated::UserEventD88B6B79B0FD8F435ED6E256A55B83AFEBF5F500
ProxyRepository.prepareClasses loaded [class UserEvent] [class UserEventD88B6B79B0FD8F435ED6E256A55B83AFEBF5F500]
FloxyMockolateFactory prepareClassRecipes prepared [class UserEvent] [class UserEventD88B6B79B0FD8F435ED6E256A55B83AFEBF5F500]
FloxyMockolateFactory prepareClassRecipes classRecipe [ClassRecipe classToPrepare=[class UserEvent] namespacesToProxy=[] proxyClass=null]
FloxyMockolateFactory prepareClassRecipes complete [class UserEvent],,mockolate.generated:UserEventD88B6B79B0FD8F435ED6E256A55B83AFEBF5F500
ProxyRepository.createWithProxyClass [class UserEventD88B6B79B0FD8F435ED6E256A55B83AFEBF5F500] ,,,,
TypeError: Error #2007: Parameter type must be non-null.
at flash.events::Event/ctor()
at flash.events::Event()
at com.fitmetrix.events::UserEvent()[/crypt/myApp/src/com/myapp/events/UserEvent.as:40]
at mockolate.generated::UserEventD88B6B79B0FD8F435ED6E256A55B83AFEBF5F500()
at org.flemit.util::ClassUtility$/createClass6()[/Users/drew/Development/workspace-burrito/flemit/flemit/src/org/flemit/util/ClassUtility.as:66]
at Function/http://adobe.com/AS3/2006/builtin::apply()
at org.flemit.util::ClassUtility$/createClass()[/Users/drew/Development/workspace-burrito/flemit/flemit/src/org/flemit/util/ClassUtility.as:57]
at org.floxy::ProxyRepository/createWithProxyClass()[/Users/drew/Development/workspace-burrito/floxy/floxy/src/org/floxy/ProxyRepository.as:94]
at mockolate.ingredients.floxy::FloxyMockolateFactory/createInstance()[/Users/abourne/Workspaces/drewbourne/mockolate/mockolate/src/mockolate/ingredients/floxy/FloxyMockolateFactory.as:122]
at mockolate.ingredients.floxy::FloxyMockolateFactory/prepareInstance()[/Users/abourne/Workspaces/drewbourne/mockolate/mockolate/src/mockolate/ingredients/floxy/FloxyMockolateFactory.as:92]
at global/asx.array::forEach()[/Users/drew/Development/workspace-oss-/asx/asx/src/asx/array/forEach.as:12]
at mockolate.ingredients.floxy::FloxyMockolateFactory/prepareInstances()[/Users/abourne/Workspaces/drewbourne/mockolate/mockolate/src/mockolate/ingredients/floxy/FloxyMockolateFactory.as:80]
at mockolate.ingredients::Mockolatier/prepareInstances()[/Users/abourne/Workspaces/drewbourne/mockolate/mockolate/src/mockolate/ingredients/Mockolatier.as:193]
at mockolate.runner.statements::InjectMockInstances/evaluate()[/Users/abourne/Workspaces/drewbourne/mockolate/mockolate/src/mockolate/runner/statements/InjectMockInstances.as:49]
at org.flexunit.internals.runners.statements::StatementSequencer/executeStep()[E:\hudson\jobs\FlexUnit4-Flex4.1\workspace\FlexUnit4\src\org\flexunit\internals\runners\statements\StatementSequencer.as:98]
at org.flexunit.internals.runners.statements::StatementSequencer/handleChildExecuteComplete()[E:\hudson\jobs\FlexUnit4-Flex4.1\workspace\FlexUnit4\src\org\flexunit\internals\runners\statements\StatementSequencer.as:141]
at org.flexunit.token::AsyncTestToken/sendResult()[E:\hudson\jobs\FlexUnit4-Flex4.1\workspace\FlexUnit4\src\org\flexunit\token\AsyncTestToken.as:107]
at Function/<anonymous>()[/Users/abourne/Workspaces/drewbourne/mockolate/mockolate/src/mockolate/runner/statements/PrepareMockClasses.as:34]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at Function/http://adobe.com/AS3/2006/builtin::apply()
at SetIntervalTimer/onTimer()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
I believe the problem is that Mockolate by default passes in NULL as a
default for constructor arguments. As the stack dump indicates:
TypeError: Error #2007: Parameter type must be non-null.
The event class doesn't agree with this...
I guess if you declare your mock like this:
[Mock(inject="false")]
public var instanceEvent:UserEvent;
And in your setUp() method instantiate it like this:
instanceEvent = stub(UserEvent,"instanceEvent", "eventType", ... other
constructor args);
That will prevent mockolate from instantiating your class by default
and letting you create it with valid ctor args at a later stage.
hope that helps (and I hope it's correct what I'm claiming here hehe)
cheers,
Roland Zwaga
> Hey Drew,
>
> I'm kinda stumped on this one. I thought it should be a simple matter of
> creating a stub for the injected event but it appears that I am missing
> something.
> I have a command which injects an event:
>
> [*Inject*]
> *public* *var* event:UserEvent;
>
> *override* *public* *function* execute():*void*
>
> {
>
> *if* ( event.usersCollection ) {
>
> *if* ( !event.usersCollection.length ) {
>
> eventDispatcher.dispatchEvent ( *new* ViewEvent (
> ViewEvent.SET_VIEW_STATE, *false*, *false*, StateConstants.NEW_USER ) );
>
> } *else* *if* ( event.usersCollection.length ) {
>
> eventDispatcher.dispatchEvent ( *new* ViewEvent (
> ViewEvent.SET_VIEW_STATE, *false*, *false*, StateConstants.SELECT_USER ) );
>
> }
>
> }
>
> }
>
> I am testing the individual conditions of the command. Here is my setup:
>
> [*Rule*]
> *public* *var* rule:MockolateRule = *new* MockolateRule();
>
> [*Mock*]
> *public* *var* instanceEvent:UserEvent;
>
> *private* *var* instanceCommand:ViewStateDecisionCommand;
>
> *private* *var* collection:ArrayCollection;
>
> [*Before*]
> *public* *function* setUp():*void*
>
> {
>
> collection = *new* ArrayCollection();
>
> instanceCommand = *new* ViewStateDecisionCommand();
>
> instanceCommand.eventDispatcher = *new* EventDispatcher();
>
> }
>
> [*After*]
>
> *public* *function* tearDown():*void*
>
> {
>
> instanceCommand = *null*;
>
> }
>
> I don't even make it into my test method before I get the following runtime
> exception (I've highlighted the actual error below, Line 40 is actually the
> event's call to *super*(type, bubbles, cancelable);):
[Mock ( inject="false")]
public var instanceEvent:UserEvent = new UserEvent ( UserEvent.GET_USERS_RESULT );
I still get the same error. So, I have to ask, can events be stubbed with a required type constructor argument?
Even if that did work, It wouldn't be desirable for me in my case as I have several types that I wish to test in this Test class.
[Test]
public function testInstanceDispatchesEvent_dispatchesEvent_instanceCommandDispatchesViewEvent():void{
collection = new ArrayCollection();
instanceCommand.event = new UserEvent ( UserEvent.GET_USERS_RESULT, false, false, collection );
var count:Number = 0;
instanceCommand.eventDispatcher.addEventListener(ViewEvent.SET_VIEW_STATE, function ( event : ViewEvent ) : Number { return count++; } );
instanceCommand.execute();
assertEquals(1,count);
}
this might be either me misunderstanding the documentation, or perhaps
this is a bug. From what I understand adding the inject=false argument
prevents Mockolate from pre-instantiating the class.
Drew, are you able to shed some light on this?
cheers,
Roland Zwaga
> Hi Roland!
>
> Thanks so much for your help. Your idea made total sense, however, it
> unfortunately didn't resolve the issue.
> I ended up removing the Rule and Mock altogether and instantiated the event
> directly into the command in the test, which resolved the problem.
> On the downside, I don't understand why your solution didn't work, If
> inject="false" prepares the class only and does not create the prepared
> Mockolate then prepare has to be needing additional constructor arguments in
> this case. But even if I provide the required type argument in the Mock
> declaration:
>
> [*Mock *( inject=*"false"*)]
> *public* *var* instanceEvent:UserEvent = *new* UserEvent (
> UserEvent.GET_USERS_RESULT );
>
> I still get the same error. So, I have to ask, can events be stubbed with a
> required type constructor argument?
> Even if that did work, It wouldn't be desirable for me in my case as I have
> several types that I wish to test in this Test class.
>
> [*Test*]
>
> *public*
> *function*testInstanceDispatchesEvent_dispatchesEvent_instanceCommandDispatchesViewEvent():
> *void*{
>
> collection = *new* ArrayCollection();
>
> instanceCommand.event = *new* UserEvent ( UserEvent.GET_USERS_RESULT, *
> false*, *false*, collection );
>
> *var* count:Number = 0;
>
> instanceCommand.eventDispatcher.addEventListener(ViewEvent.SET_VIEW_STATE,
> *function* ( event : ViewEvent ) : Number { *return* count++; } );
>
> instanceCommand.execute();
>
> assertEquals(1,count);
>
> }
>
>
with events and VOs, I have a script that makes an extending class "SomeEventSupport" which automatically stubs its own values (unless provided). This isolates the test from the constructor of the event. I wouldn't go so far as to mock an event as there's no behaviour to stub / verify, and mocking with values provided for the constructor doesn't help you as you're not isolated from the constructor args for that class.
So - "direct instantiation vs mockolate stub" misses the 3rd option - a support class that populates its own constructor args. I usually pass a single property (a uint) that I use to make the other properties unique - eg passing 3 to an item with a title would give it "Title3" as that property.
For types you can either isolate that by having more than one support class per type, or using the constant itself.
Stray
[Rule]
public var rule:MockolateRule = new MockolateRule();
[Mock ( type = "partial", args = "userEventArgs" )]
public var instanceEvent:UserEvent;
public var userEventArgs:Array = [UserEvent.GET_USERS_RESULT, false, false, collection];
private var instanceCommand:ViewStateDecisionCommand;
private var collection:ArrayCollection;
[Before]
public function setUp():void
{
collection = new ArrayCollection();
instanceCommand = new ViewStateDecisionCommand();
instanceCommand.eventDispatcher = new EventDispatcher();
}
And then in the test I needed to set the userCollection argument to the collection AC, stub the instanceEvent, and assign the instanceCommand.event property to the stub:
[Test]
public function testInstanceDispatchesEvent_dispatchesEvent_instanceCommandDispatchesViewEvent():void{
instanceEvent.usersCollection = collection;
stub(instanceEvent);
instanceCommand.event = instanceEvent;