drewbourne/mockolate

Strange error when creating strict mock

Opened this issue · 11 comments

hob commented

Just upgraded to 0.12.2. I'm getting an odd error on just a couple of our existing test cases. We're preparing the mocks for this particular strict the same way we are with others. Haven't been able to find anything that makes this case unique yet.

Error
at mockolate.ingredients::InstanceRecipeBuilder/withClassRecipe(InstanceRecipeBuilder.as:21)
at mockolate.ingredients::Mockolatier/strict(Mockolatier.as:172)
at global/mockolate::strict(strict.as:28)
at com.workday.ui.flex.view.controls.workFeedClasses::WorkFeedFilterMenuPresenterTest/setup(WorkFeedFilterMenuPresenterTest.as:54)
at Function/http://adobe.com/AS3/2006/builtin::apply
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::ExpectAsync/sendComplete(ExpectAsync.as:560)
at org.flexunit.internals.runners.statements::ExpectAsync/handleAsyncEventFired(ExpectAsync.as:431)
at flash.events::EventDispatcher/dispatchEventFunction
at flash.events::EventDispatcher/dispatchEvent
at org.flexunit.async::AsyncHandler/handleEvent(AsyncHandler.as:156)
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

Pretty sure I fixed that, I'll have to check which version was affected.

cheers,
Drew

On Thu, Nov 10, 2011 at 3:13 PM, Hob spillane <
reply@reply.github.com>wrote:

Just upgraded to 0.12.2. I'm getting an odd error on just a couple of our
existing test cases. We're preparing the mocks for this particular strict
the same way we are with others. Haven't been able to find anything that
makes this case unique yet.

Error
at
mockolate.ingredients::InstanceRecipeBuilder/withClassRecipe(InstanceRecipeBuilder.as:21)
at mockolate.ingredients::Mockolatier/strict(Mockolatier.as:172)
at global/mockolate::strict(strict.as:28)
at
com.workday.ui.flex.view.controls.workFeedClasses::WorkFeedFilterMenuPresenterTest/setup(WorkFeedFilterMenuPresenterTest.as:54)
at Function/http://adobe.com/AS3/2006/builtin::apply
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::ExpectAsync/sendComplete(ExpectAsync.as:560)
at
org.flexunit.internals.runners.statements::ExpectAsync/handleAsyncEventFired(ExpectAsync.as:431)
at flash.events::EventDispatcher/dispatchEventFunction
at flash.events::EventDispatcher/dispatchEvent
at org.flexunit.async::AsyncHandler/handleEvent(AsyncHandler.as:156)
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


Reply to this email directly or view it on GitHub:
#49

hob commented

I grabbed the latest code & compiled from source and this issue seems to be gone. I'm seeing something else strange though.

It seems like anywhere where we were doing assignments inside of expect()s, we're now getting errors thrown. For example:

        var mgr:ContextMenuManager = ContextMenuManager.getInstance();
        var target:IContextMenuTarget = strict(IContextMenuTarget);
        record(target);
        expect(target.contextMenu = mgr.getContextMenuInstance());
        replay(target);
        mgr.registerContextMenuTarget(target);
        verify(target);

That expect() now throws an exception where it did not before. The code never even gets to the replay() call.

hob commented

And it's back. Sort of... Now I'm getting the error only on some runs, and the stack trace is slightly different. Note the 1st line now has a little more verbage.

Error: InstanceRecipeBuilder.withClassRecipe
at mockolate.ingredients::InstanceRecipeBuilder/withClassRecipe(InstanceRecipeBuilder.as:21)
at mockolate.ingredients::Mockolatier/strict(Mockolatier.as:172)
at global/mockolate::strict(strict.as:28)
at com.workday.ui.flex.view.controls.workFeedClasses::WorkFeedHeaderPresenterTest/setup(WorkFeedHeaderPresenterTest.as:60)
...

hob commented

Found one commonality. In each of the cases that fails, the strict or nice mock is getting created in setup():

    public function setup():void
    {
        this.view = strict(ICommandSetButton);
    }

I need to update the docs, record() and replay() are deprecated as they are
unneeded. Your example should be written as:

var mgr:ContextMenuManager = ContextMenuManager.getInstance();
var target:IContextMenuTarget = strict(IContextMenuTarget);
expect(target.contextMenu = mgr.getContextMenuInstance());
mgr.registerContextMenuTarget(target);
verify(target);

What error is the expect() throwing?

Are you using Flash Builder? That stack trace looks like its truncated the
first line which is what FB does in its internal FlexUnit Results view. If
you check the flashlog it should have the full stack trace which should
tell you which Class Mockolate was trying to instantiate that had not yet
been prepared.

Any chance you could share a minimal project that exhibits this issue?

cheers
Drew

On Fri, Nov 11, 2011 at 6:34 AM, Hob spillane <
reply@reply.github.com>wrote:

Found one commonality. In each of the cases that fails, the strict or
nice mock is getting created in setup():

           public function setup():void
           {
                   this.view = strict(ICommandSetButton);
            }

Reply to this email directly or view it on GitHub:
#49 (comment)

hob commented

Attaching a simple project. This exhibits the error throwing from expect(), even after I've removed record() & replay(). Still working on getting the other issue to show up in a stand-alone project. Not sure if it'll be possible, but if you'd like we can setup a screenshare so you can see my test suite running. I've got your source linked in, so you should be able to step thru in my environment.

-Hob

On Nov 10, 2011, at 5:21 PM, Drew Bourne wrote:

I need to update the docs, record() and replay() are deprecated as they are
unneeded. Your example should be written as:

var mgr:ContextMenuManager = ContextMenuManager.getInstance();
var target:IContextMenuTarget = strict(IContextMenuTarget);
expect(target.contextMenu = mgr.getContextMenuInstance());
mgr.registerContextMenuTarget(target);
verify(target);

What error is the expect() throwing?

Are you using Flash Builder? That stack trace looks like its truncated the
first line which is what FB does in its internal FlexUnit Results view. If
you check the flashlog it should have the full stack trace which should
tell you which Class Mockolate was trying to instantiate that had not yet
been prepared.

Any chance you could share a minimal project that exhibits this issue?

cheers
Drew

On Fri, Nov 11, 2011 at 6:34 AM, Hob spillane <
reply@reply.github.com>wrote:

Found one commonality. In each of the cases that fails, the strict or
nice mock is getting created in setup():

          public function setup():void
          {
                  this.view = strict(ICommandSetButton);
           }

Reply to this email directly or view it on GitHub:
#49 (comment)


Reply to this email directly or view it on GitHub:
#49 (comment)

The tests for using an Invocation to define an Expectation (like: expect(target.contextMenu = mgr.getContextMenuInstance()))) only use instances created with nice().

In the case of strict() Mockolate is throwing an error too early because there are no expectations defined for the invocation. Which happens before the call to expect() even happens. Which is what strict() is meant to be doing.

Then implementation of strict() needs to be changed to record which invocations don't have expectations defined then throw an error during the verification phase instead of immediately.

hob commented

I haven't read extensively through your code, but that's why I thought you needed record() & replay()... So that you could tell the difference between an expectation and an invocation. Could you not also just trap MockolateErrors in expect since you know that you're creating an expectation.

Anyway. Not a big deal. For now I've just re-written those expectations using mock(). My bigger concern is the other error (Error: InstanceRecipeBuilder.withClassRecipe). I haven't been able to get that working in a stand-alone project yet.

My flashlog is a bit of a mystery... All it's showing is:

Warning: 'flash' has no property 'prototype'
Warning: 'flash' has no property 'prototype'
INFO: Initialize Flex Support

I'd love to trap the error except its not a block thats being passed to expect() it is the result of the invocation. I use heuristics in the proxy to take a best guess at what should happen.

Expanding this example into execution order:

expect(target.contextMenu = arg(ContextMenu));

Becomes:

// creates a matcher for instanceOf(ContextMenu)
// adds to the pending expectations arguments
// returns null
arg( ContextMenu ); 

// attempts to assign the result of the arg() call which is null
// records an invocation
// returns null
target.contextMenu = null;

// finds the last recorded invocation
// creates an expectation for the setter
// use the matcher created from arg() to match arguments
expect( null );

As long as people keep it simple there is no need for record() or replay().

For complicated cases I am considering adding something like an expecting(Function) as a block within which expectations should be defined. eg:

expecting(function():void {
    expect(target.contextMenu = arg(ContextMenu));
});

For the other error is it when you run the test case by itself or as part of the suite?

hob commented

Its only as part of the suite, and only sometimes. Definitely seems to happen more as I go. As if the fewer resources flash has, the more likely the error is to crop up.

hob commented

I switched to Rules instead of prepare() and the test suite seems to be running great. I'll leave this open so you have a place to track deferring the exception to validation phase?