drewbourne / mockolate

fake chocolate, mock objects and test spies for AS3
http://mockolate.org/
MIT License
145 stars 27 forks source link

Strange error when creating strict mock #49

Open hob opened 13 years ago

hob commented 13 years ago

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

drewbourne commented 13 years ago

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: https://github.com/drewbourne/mockolate/issues/49

hob commented 13 years ago

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 13 years ago

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 13 years ago

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);
    }
drewbourne commented 13 years ago

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: https://github.com/drewbourne/mockolate/issues/49#issuecomment-2699957

hob commented 13 years ago

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: https://github.com/drewbourne/mockolate/issues/49#issuecomment-2699957


Reply to this email directly or view it on GitHub: https://github.com/drewbourne/mockolate/issues/49#issuecomment-2702101

drewbourne commented 13 years ago

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 13 years ago

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

drewbourne commented 13 years ago

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 13 years ago

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 13 years ago

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?