OCMOCK_ANY for values

Post a reply


This question is a means of preventing automated form submissions by spambots.
Smilies
:D :) ;) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :!: :?: :idea: :arrow: :| :mrgreen: :geek: :ugeek:
BBCode is ON
[img] is ON
[flash] is OFF
[url] is OFF
Smilies are ON
Topic review
   

Expand view Topic review: OCMOCK_ANY for values

Re: OCMOCK_ANY for values

Post by Guest » 30 Jan 2013, 10:19

... Sorry, that might have been less than polite. I'll try to make this change myself, including unit tests and other specific pointer types (such as const char *, which is also not encoded as ^something ). I hope to find time for it in the next few days.
BTW, another small question: the constant value indicating anyPointer is just a fixed address, which I suppose wouldn't be used for objects but I'm not sure about general pointers... Maybe it would be better to define a static variable in OCMock, and return a pointer to it?

Re: OCMOCK_ANY for values

Post by Guest » 27 Jan 2013, 16:31

Hi,
Any chance of a quick change implementing this specifically for selector arguments (SEL)?
+[OCMArg anyPointer] does match selectors (preventing compiler warnings) but +[OCMArg resolveSpecialValues] doesn't identify it, since the SEL type is indicated by ':' rather than '^' in the method signature. This seems easy to change, and is useful for many APIs which take targets and selectors.
Thanks

Re: OCMOCK_ANY for values

Post by erik » 28 Sep 2012, 00:01

This sounds interesting. I am not sure how this would behave on multiple invocations of the stubbed method. Would you keep a copy of the stack? Maybe some code would help. ;)

Re: OCMOCK_ANY for values

Post by shem » 16 Aug 2012, 11:07

Even better solution now that I've given it more thought:

Implement a stack of parameter matcher objects (ie. OCMConstraint). This could be a new implementation of OCMArg's various parameter matchers.

Add various methods to OCMArg:
- (int)anyInt;
- (float)anyFloat;
etc.

And, when these are called, you add the generic 'any' matcher to the stack (representing the array of parameters for the method), and just return a dummy value of the primitive type. Then, once the recorded expectation gets set (when the method attempts to be forwarded), you just pop everything off the stack, and record those inside the OCMockRecorder and evaluate them all later. Then, you can effectively match any argument - and it creates a good abstraction. I may help flush out an implementation here if you'd like. This could also be used for nice ways of capturing input as well (ala the 'Capture' interface of EasyMock).

I like it.

Re: OCMOCK_ANY for values

Post by shem » 16 Aug 2012, 10:03

Here are a couple of new ideas here, because this is a big hole in the testing framework in my opinion:

(1) Extending OCMockRecorder to have a more generalized method of ignoring matching any argument besides the current mechanism that only works with objects (and has an interesting implementation for pointers...)

- (id)ignoresArgAtIndex:(NSUInteger)index; //(or maybe just restrict it to non-object 'values' only, which may look like 'ignoresValueArgAtIndex')

And then in the 'matchesInvocation' method, you could just check if that particular index had been registered as needing to be ignored, and if so, ignoring that particular argument. Seems pretty simple, and technically still fits the recorder mantra.

(2) Another way of achieving this could be by just providing a 'alwaysMatchesInvocation:^(NSInvocation invocation /* or potentially just providing the array of parameters */) {...}' (assuming the arg types and arg count is the same as the method signature) bit on the recorder, and then leaving the assertion of what's allowed and disallowed explicitly to the definition in the block. The default behavior could be to fallback to the original matching behavior if the matcher fails. It's a bit heavy handed, but could work -- very similar to the 'doBlock' variant, except this one would be evaluated to determine if the invocation should match.

Re: OCMOCK_ANY for values

Post by chrispix » 16 Feb 2012, 00:33

This continues to plague me. What about allowing for selector-based matching? Something like:

Code: Select all
[mockController expect:@selector(someMethodWithInt:otherIntArgument:)];
[mockController reject:@selector(someMethodWithInt:otherIntArgument:)];
[[mockController stub:@selector(someMethodWithInt:otherIntArgument:)] andReturn:@"foo"];


Using either of these would ignore all arguments and match any invocation. It wouldn't help when it's important to match one or more arguments specifically, but I suspect it would work for 90% of cases.

Re: OCMOCK_ANY for values

Post by dvmorris » 08 Jul 2011, 04:51

Has there been any progress on this front? I'm really stuck with some functions that I can't mock in my app because they have NSInteger parameters.

Thanks,
Dave

Re: OCMOCK_ANY for values

Post by skrul » 11 Mar 2011, 18:54

I think there is still an issue with methods that have multiple same-typed primitive arguments where you want to "any match" some based on a special registered value, and exact match others on that same value. Building on chrispix's example:

int alwaysMatchInt = 0;
[mockController alwaysMatch:OCMOCK_VALUE(alwaysMatchInt)];
[[mockController stub] someMethodWithInt:alwaysMatchInt otherIntArgument:0];

The matcher would not know the difference between the first argument that matches the registered "any" value and the second argument that you want to explicitly match the value 0. You could argue that it is up to the test writer to choose a better value for alwaysMatchInt, but that seems a little brittle.

For this reason, I think any solution is going to have to include argument names rather than values. Maybe you can pass stub/expect a list of argument names that should always match:

[[mockController stubWithAny:@"otherIntArgument", nil] someMethodWithInt:0 otherIntArgument:0];

Re: OCMOCK_ANY for values

Post by erik » 23 Feb 2011, 22:11

That's a new idea; not ideal, but the whole situation is not ideal. I like the direction this is going but I think it needs some refinement to make it more palatable to the user. Maybe we can create a macro that, as a side effect, does the registration of the special value? Hm...

Re: OCMOCK_ANY for values

Post by chrispix » 16 Feb 2011, 00:30

I'm running into this problem more and more these days.

What if it were up to the caller to specify the special value(s) which should always match? For example:
Code: Select all
UIViewController *controller = ...
id mockController = [OCMockObject partialMockForObject:controller];

CGRect alwaysMatchCGRect = CGRectZero;
int alwaysMatchInt = 0;
[mockController alwaysMatch:OCMOCK_VALUE(alwaysMatchCGRect)];
[mockController alwaysMatch:OCMOCK_VALUE(alwaysMatchInt)];

[[mockController stub] presentPopoverFromRect:alwaysMatchCGRect inView:[OCMarg any] permittedArrowDirections:alwaysMatchInt animated:YES];


Then OCMockRecorder would keep a set of alwaysMatchers:
Code: Select all
-(void)alwaysMatch:(NSValue *)value {
   [[self alwaysMatchers] andObject:value];
}


And matchesInvocation would pass if it finds one of those values:
Code: Select all
- (BOOL)matchesInvocation:(NSInvocation *)anInvocation {

...

      if([recordedArg isKindOfClass:[NSValue class]]) {
         if ([alwaysMatchers containsObject:recordedArg]) {
            recordedArg = [OCMArg any];
         }
         recordedArg = [OCMArg resolveSpecialValues:recordedArg];         
      }

Top

cron