Cannot stub a method (with multiple arguments) of a protocol mock/fake

65 views
Skip to first unread message

jby...@kineticcafe.com

unread,
Feb 18, 2015, 4:08:48 PM2/18/15
to cedar-...@googlegroups.com
Hi,

I'm having an issue where I'm getting an exception when I try to stub a method (that takes in multiple arguments) of a fake of a protocol. My code snippet is :

id<CedarDouble> newDelegate = nice_fake_for(@protocol(NSScrollViewDelegate));
subject.delegate = (id<NSScrollViewDelegate>)newDelegate;
spy_on(delegate);
newDelegate stub_method("scrollViewWillEndDragging:targetContentOffset:").with(Arguments::anything, Arguments::anything).and_return(YES);

Note that the method name of the protocol that I'm trying to stub has the following signature: scrollViewWillEndDragging:targetContentOffset: and takes in 2 arguments. The exception get thrown at the line highlighted in red. I've traced it down to the "protocol_hasSelector" method in the CDRProtocolFake.mm file and it looks like the fake defined doesn't have that method signature within its list (when I clearly have it in the list of method in my protocol). The debug description of the exception thrown is:

Attempting to stub method <scrollViewWillEndDragging:targetContentOffset:>, which double <Fake implementation of NSScrollViewDelegate protocol(s)> does not respond to

Any assistance would be greatly appreciated.

Thanks

JB


Sam Coward

unread,
Feb 18, 2015, 4:49:46 PM2/18/15
to cedar-...@googlegroups.com
Are you forward declaring the protocol anywhere in your code? (i.e. doing @protocol NSScrollViewDelegate; instead of importing it).

We've noticed that the method signature information is sometimes missing from the objc runtime when the codebase contains these, and replacing them with #imports usually works.

If anyone has any insight into why the runtime does this, I'm all ears.

--
Sam

--
You received this message because you are subscribed to the Google Groups "Cedar Discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cedar-discus...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

jby...@kineticcafe.com

unread,
Feb 19, 2015, 10:48:40 AM2/19/15
to cedar-...@googlegroups.com
Hey Sam,

The only place where the methods of this my protocol have been declared is in its own header file and nowhere else and I'm importing the header file in my spec. Not sure why those methods signatures are not being generated and stored in the CDRProtocolFake instance. Thoughts?

Andrew Kitchen

unread,
Feb 19, 2015, 11:13:32 AM2/19/15
to cedar-...@googlegroups.com, cedar-...@googlegroups.com
The methods are not loaded into the runtime in some cases. It's a frustrating quirk, to say the least, but not a bug in cedar per se. There is an apple doc which mentions this, I will have to try to dig it up later.

If you try to stub one of these methods when this is happening, and you step the cedar code, you will see where the runtime fails to return the method descriptions.

Importing the protocol isn't enough. There must be a class loaded which implements it. Although cedar generates a class for this at runtime, it isn't always enough. One workaround is to implement an empty class in your spec which conforms to the protocol, sad as that sounds. I have been thinking of adding a macro for this inside CDR_fake_for

jby...@kineticcafe.com

unread,
Feb 19, 2015, 11:37:43 AM2/19/15
to cedar-...@googlegroups.com
Hey Andrew,

Yea this is what I did. I manually created a dummy class inheriting from NSObject and implementing my protocol. Thanks for the follow-up.

Sam Coward

unread,
Feb 19, 2015, 2:10:50 PM2/19/15
to cedar-...@googlegroups.com
Yeah - it would be good to understand why this happens to see if we can find a way that doesn't use macros.

I've tried to construct a trivial test case for this problem before without success; usually by adding a protocol to the app target with the only code reference being in the fake_for(@protocol(MyProtocol)) call in the tests. In such trivial examples, it seems that this reference in the code is enough for the compiler to bake the protocol information into the binary.

I've tested this on Xcode 6.1.1 against iOS 8.1 and 7.1 and OS X 10.10 running tests as both bundle or a suite.

Discussions on cocoabuilder.com seem to confirm that folks expect that either the presence of a concrete implementation or a @protocol() reference should result in the compiler including it; of course this isn't from the horse's mouth.

--
Sam

Sam Coward

unread,
Mar 4, 2015, 5:10:50 PM3/4/15
to cedar-...@googlegroups.com
Just another data point on this issue: I was helping a team out today with this problem, and declaring and implementing a dummy class which conforms to the protocol at the top of the Spec did not work for them.

We implemented +load on this and can confirm that the class loads, but the stubbing still fails.

The changes made by the team to trigger this were moving a protocol implementation off the AppDelegate into other objects.

Adding the protocol back to the AppDelegate made everything work again.

I'm still not sure what the big picture around this problem looks like, but hopefully it's another piece of the jigsaw puzzle.

--
Sam
Reply all
Reply to author
Forward
0 new messages