OCMock: Make a stub do something - objective-c

I'm getting used to OCMock. Coming from a Java/JMock background I'm now looking for the ability to say [[[myMock stub] returnValueFromCustomMethod] someMockedMethod]; where returnValueFromCustomMethod is defined in the test class. I was originally thinking something along the terms of [[[myMock stub] usingSelector:#selector(myMethod:)] someMockedMethod]; but after writing I wonder if my first approach makes more sense. Either way, could someone show me if and how this can be done?

My original answer was off-track: OCMock doesn't support this! If you wanted to change OCMock to support this, you would need to do something like adding a BOOL returnValueIsFromInvocation field to OCMockRecorder, and add a method to set this up:
- (id)andReturnResultOfInvocation:(NSInvocation *)anInvocation {
returnValueIsFromInvocation = YES;
returnValueIsBoxed = NO;
returnValueShouldBeThrown = NO;
[returnValue autorelease];
returnValue = [anInvocation retain];
return self;
}
Then teach setUpReturnValue to call the invocation (changes are in bold):
- (void)setUpReturnValue:(NSInvocation *)anInvocation
{
if (returnValueIsFromInvocation) {
NSInvocation *returnValueInvocation = (NSInvocation *)returnValue;
[returnValueInvocation invoke];
void *buffer = malloc([[anInvocation methodSignature] methodReturnLength]);
[returnValueInvocation getValue:buffer];
[anInvocation setReturnValue:buffer];
free(buffer);
}
else if(returnValueShouldBeThrown)
{
#throw returnValue;
}
else if(returnValueIsBoxed)
{
if(strcmp([[anInvocation methodSignature] methodReturnType],
[(NSValue *)returnValue objCType]) != 0)
[NSException raise:NSInvalidArgumentException
format:#"Return value does not match method signature."];
void *buffer = malloc([[anInvocation methodSignature] methodReturnLength]);
[returnValue getValue:buffer];
[anInvocation setReturnValue:buffer];
free(buffer);
}
else
{
const char *returnType = [[anInvocation methodSignature] methodReturnType];
const char *returnTypeWithoutQualifiers = returnType + (strlen(returnType) - 1);
if(strcmp(returnTypeWithoutQualifiers, #encode(id)) == 0)
[anInvocation setReturnValue:&returnValue];
}
}
This change is difficult to do by introducing subclasses because you have to override the methods that return OCMockRecorders (like stub, expect and so on) but the concrete subclasses of OCMockObject (OCClassMockObject and OCProtocolMockObject) are hidden by the framework.

Related

OCMVerify crashes test after a mocked callback

I have a method from a class under tests which takes two delegates: the second delegate will call a method after the first delegate will be called with a callback function as input.
#implemenation ClassUnderTest
...
- (void) methodWithMultipleCallbacks: (id<MyDelegate>) delegate
withSecondDelegate: (id<MyDelegateWithCallback>) delegateWithCallback {
for (int i = 0; i < 2; i++){
Callback callback = ^(int input) {
NSLog(#"%d-th callback", i);
NSLog(#"input = %d", input);
};
[delegateWithCallback fetchInt:callback];
}
[delegate delegateDoStuff:32];
}
But the strange thing happens: I tried to test it using OCMock, mocking both delegates, but the crashes, and I got a EXEC_BAD_ACCESS.
I am utterly confused and would really appreciate any help here! Here's the test function
- (void) testWithMultipleCallbacks {
id <MyDelegateWithCallback> mockDelegateWithCallback = OCMProtocolMock(#protocol(MyDelegateWithCallback));
OCMStub([mockDelegateWithCallback fetchInt:[OCMArg any]]).andDo(^(NSInvocation *invocation) {
void (^block)(int) = NULL;
[invocation getArgument:&block atIndex:2];
NSLog(#"got here");
block(33);
});
[_classUnderTest methodWithMultipleCallbacks: _mockedDelegate withSecondDelegate: mockDelegateWithCallback];
OCMVerify(OCMTimes(1), [_mockedDelegate delegateDoStuff:[OCMArg any]]);
}

How can I optimize this huge if/else if block within observeValueForKey

I have a controller that is registered as an observer for a LOT of properties on views. This is our -observeValueForKeyPath:::: method:
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void*)context
{
if( context == kStrokeColorWellChangedContext )
{
[self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kStrokeColorProperty];
}
else if( context == kFillColorWellChangedContext )
{
[self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kFillColorProperty];
}
else if( context == kBodyStyleNumChangedContext )
{
[self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kBodyStyleNumProperty];
}
else if( context == kStyleChangedContext )
{
[self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kStyleProperty];
}
else if( context == kStepStyleChangedContext )
{
[self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kStepStyleProperty];
}
else if( context == kFirstHeadStyleChangedContext )
{
[self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kFirstHeadStyleProperty];
}
else if( context == kSecondHeadStyleChangedContext )
{
[self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:kSecondHeadStyleProperty];
}
And there's actually about 3x more of these else if statements.
One thing you can see is that each block has the same code, which makes me think that it's possible to optimize this.
My initial thought was to have an NSDictionary called keyPathForContextDictionary where the keys are the constants with the Context suffix (of type void*), and the values are the appropriate string constants, denoted by the Property suffix
Then this method would only need one line:
[self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:keyPathForContextDictionary[context]];
Note that I need to use a data structure of some sort to identify which keyPath to use, and I can't simply use the keyPath argument passed into the method. This is because there are multiple views that have the same property I'm observing (for example, color wells have the color property). So each view needs to determine a unique keypath, which is currently being determined based off of the context
The problem with this is that you cannot use void* as keys in an NSDictionary. So... does anybody have any recommendations for what I could do here?
EDIT:
Here's an example of how the constants are defined:
void * const kStrokeColorWellChangedContext = (void*)&kStrokeColorWellChangedContext;
void * const kFillColorWellChangedContext = (void*)&kFillColorWellChangedContext;
void * const kBodyStyleNumChangedContext = (void*)&kBodyStyleNumChangedContext;
void * const kStyleChangedContext = (void*)&kStyleChangedContext;
NSString *const kStrokeColorProperty = #"strokeColor";
NSString *const kFillColorProperty = #"fillColor";
NSString *const kShadowProperty = #"shadow";
NSString *const kBodyStyleNumProperty = #"bodyStyleNum";
NSString *const kStyleProperty = #"style";
The type void * is not so much a type unto itself that you have to match, as it is "generic pointer". It's used for the context argument precisely so that you can use any underlying type that you like, including an object type. All you have to do is perform the proper casts.
You can therefore change your kTHINGYChangedContexts to be NSStrings or any other object you like very easily, and then use them as keys in your context->key path mapping.
Start with:
NSString * const kStrokeColorWellChangedContext = #"StrokeColorWellChangedContext";
When you register for observation, you must perform a bridged cast:
[colorWell addObserver:self
forKeyPath:keyPath
options:options
context:(__bridge void *)kStrokeColorWellChangedContext];
Then when the observation occurs, you do the reverse cast:
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void*)ctx
{
NSString * context = (__bridge NSString *)ctx;
// Use context, not ctx, from here on.
}
And proceed to your key path lookup from there.
Josh Caswell had a great answer, but I didn't want to modify the type of our constants into NSStrings*
So a solution instead, was to cast the void* into NSValues w/ -valueWithPointer. This way I could use the void* as keys in my dictionary
Here's the code:
NSString *toolKeyPath = [[ToolController keyPathFromContextDictionary] objectForKey:[NSValue valueWithPointer:context]];
if( toolKeyPath )
{
if( [change objectForKey:NSKeyValueChangeNewKey] == (id)[NSNull null] )
{
[self setValue:nil forKey:toolKeyPath];
}
else
{
[self setValue:[change objectForKey:NSKeyValueChangeNewKey] forKey:toolKeyPath];
}
}
And the dictionary:
+(NSDictionary*) keyPathFromContextDictionary
{
return #{
[NSValue valueWithPointer:kStrokeColorWellChangedContext] : kStrokeColorProperty,
[NSValue valueWithPointer:kFillColorWellChangedContext] : kFillColorProperty,
[NSValue valueWithPointer:kBodyStyleNumChangedContext] : kBodyStyleNumProperty,
[NSValue valueWithPointer:kStyleChangedContext] : kStyleProperty,
[NSValue valueWithPointer:kStepStyleChangedContext] : kStepStyleProperty,
[NSValue valueWithPointer:kFirstHeadStyleChangedContext] : kFirstHeadStyleProperty,
[NSValue valueWithPointer:kSecondHeadStyleChangedContext] : kSecondHeadStyleProperty,
[NSValue valueWithPointer:kShadowChangedContext] : kShadowProperty,
[NSValue valueWithPointer:kStrokeWidthChangedContext] : kStrokeWidthProperty,
[NSValue valueWithPointer:kBlurRadiusChangedContext] : kBlurRadiusProperty,
[NSValue valueWithPointer:kFontSizeChangedContext] : kFontSizeProperty
};
}

Better way to observe in ReactiveCocoa

I'm still new to ReactiveCocoa. I wanted to simply add an observer to a field, so did it like this:
[_countryPicker rac_observeKeyPath:#"value" options:nil observer:self block:^(VBCountry* value, NSDictionary* change)
{
if ([_mobileField.textField.text length] == 0)
{
[_mobileField.textField setText:[NSString stringWithFormat:#"+%i", value.dialCode]];
}
}];
With block callback, and no need to explicitly detach the observer, this is already better than old-style KVO.
However, is this a low-level method to which there's a higher level of abstraction? If so, is it OK to call this method directly? And what's the better/higher way to do it?
I'd advise against depending on the direct KVO methods. They're really an implementation detail.
Let's progressively re-write that with idiomatic RAC operators.
First we'll just replace the direct KVO code with RACObserve:
[RACObserve(_countryPicker, value) subscribeNext:^(VBCountry *value) {
if ([_mobileField.textField.text length] == 0)
{
[_mobileField.textField setText:[NSString stringWithFormat:#"+%i", value.dialCode]];
}
}];
Then we'll replace the if and string formatting with -filter: and -map::
[[[RACObserve(_countryPicker, value) filter:^(id _) {
return [_mobileField.textField.text length] > 0;
}] map:^(VBCountry *value) {
return [NSString stringWithFormat:#"+%i", value.dialCode];
}] subscribeNext:^(NSString *text) {
[_mobileField.textField setText:text];
}];
Finally we'll use the RAC macro to make the assignment over time explicit:
RAC(_mobileField.textField, text) = [[RACObserve(_countryPicker, value) filter:^(id _) {
return [_mobileField.textField.text length] > 0;
}] map:^(VBCountry *value) {
return [NSString stringWithFormat:#"+%i", value.dialCode];
}];

Objective C: How to Write a Instantiating Custom Init

Very basic question, but I have an error in my code that can only be answered by one assumption: my class isn't being instantiated!
I haven't written much in Objective C in some time, and I was never really good, so please point out even the most painfully obvious.
I am using:
ObjectSelectionViewController *length = [[ObjectSelectionViewController alloc] initWithMeasureType:0];
ObjectSelectionViewController *mass = [[ObjectSelectionViewController alloc] initWithMeasureType:1];
ObjectSelectionViewController *volume = [[ObjectSelectionViewController alloc] initWithMeasureType:2];
NSLog(#"%#", [length measurementType]);
NSLog(#"%#", [mass measurementType]);
NSLog(#"%#", [volume measurementType]);
The NSLogs return whichever measurement was assigned last, regardless of the separate allocs and inits.
Here is the constructor of the ObjectSelectionViewController class:
#import "ObjectSelectionViewController.h"
#implementation ObjectSelectionViewController
NSString *measurementType;
-(ObjectSelectionViewController*) initWithMeasureType:(int)value
{
switch (value) {
case 0: // Length
measureType = #"Length";
break;
case 1: // Mass
measureType = #"Mass";
break;
case 2: // Volume
measureType = #"Volume";
break;
}
return self;
}
-(NSString*) measurementType
{
return measureType;
}
Thanks for the help, it's driving me crazy!
You need to make measureType an instance variable, so that each object of this type that you create has its own copy:
#interface ObjectSelectionViewController : NSViewController {
NSString * measureType; // Declare an NSString instance variable
}
- (id) initWithMeasureType: (int)value;
#end
As it is, there is only one copy of the variable, and every time you instantiate a new object, its value changes. Since each instance is referring to the same copy, they all get the same value:
ObjectSelectionViewController *length = [[ObjectSelectionViewController alloc] initWithMeasureType:0];
NSLog(#"%#", [length measurementType]); // Prints "Length"
ObjectSelectionViewController *mass = [[ObjectSelectionViewController alloc] initWithMeasureType:1];
NSLog(#"%#", [length measurementType]); // Prints "Mass"
You also need to change your init... method as mentioned by other answerers:
- (id) initWithMeasureType: (int)value {
// Call superclass's initializer
self = [super init];
if( !self ) return nil;
switch (value) {
case 0: // Length
measureType = #"Length";
break;
case 1: // Mass
measureType = #"Mass";
break;
case 2: // Volume
measureType = #"Volume";
break;
}
return self;
}
Since you are assigning a literal string to the instance variable, you do not need to worry about managing its memory; if you were doing anything more complicated, you would probably do well by declaring a property.
Another note: initializer methods should always return id, a generic object pointer, to allow subclasses to work properly.
You need to call [super init] first, like this:
-(id) initWithMeasureType:(int)value
{
if ((self = [super init]))
{
switch (value) {
case 0: // Length
measureType = #"Length";
break;
case 1: // Mass
measureType = #"Mass";
break;
case 2: // Volume
measureType = #"Volume";
break;
}
}
return self;
}
Constructors are a convention in Objective-C rather than a language feature. So, for example, there's no automatic calling of parent constructors (just like you wouldn't expect any other overridden method to call its parent implementations). Similarly, the names used for constructors are just conventions, so the compiler knows nothing of init. With that in mind, what you actually want as your constructor is:
-(id) initWithMeasureType:(int)value
{
if((self = [super init]))
{
switch (value) {
case 0: // Length
measureType = #"Length";
break;
case 1: // Mass
measureType = #"Mass";
break;
case 2: // Volume
measureType = #"Volume";
break;
}
}
return self;
}
Assuming measureType is an instance variable (declared as part of the interface, generally speaking) and not a global then that should do what you want.
In your custom init method you just need to start with:
self = [super init];
- (id) initWithMeasureType: (int)value {
// Call superclass's initializer
self = [super init];
if( !self ) return nil;
switch (value) {
case 0: // Length
measureType = #"Length";
break;
case 1: // Mass
measureType = #"Mass";
break;
case 2: // Volume
measureType = #"Volume";
break;
}
return self;
}

How can I know whether an instance implements a method in Objective-C?

I would like to know if an instance implements a specific method. I could use respondsToSelector: but it returns YES if the instance inherits the method...
I could loop through the methods of class_copyMethodList(), but since I might want to check a lot of instances, I wanted to know if there was a simpler solution (like repondsToSelector:, but restricted to the class itself...)
edit: since I really think there is no function or method doing that, I wrote mine. Thanks for your answers, here is the method if it can be of any use :
+ (BOOL)class:(Class)aClass implementsSelector:(SEL)aSelector
{
Method *methods;
unsigned int count;
unsigned int i;
methods = class_copyMethodList(aClass, &count);
BOOL implementsSelector = NO;
for (i = 0; i < count; i++) {
if (sel_isEqual(method_getName(methods[i]), aSelector)) {
implementsSelector = YES;
break;
}
}
free(methods);
return implementsSelector;
}
It's probably easier to check whether the method your own class returns is the same or different than the method your superclass returns.
if ([[obj class] instanceMethodForSelector:sel] != [[obj superclass] instanceMethodForSelector:sel]) {
NSLog(#"%# directly implements %#", [obj class], NSStringFromSelector(sel));
}
instance responds and super does not:
-(BOOL) declaresSelector:(SEL)inSelector {
return [self respondsToSelector:inSelector] && ![super respondsToSelector:inSelector];
}
instance responds and is different than super:
-(BOOL) implementsSelector:(SEL)inSelector {
return [self respondsToSelector:inSelector] && !( [super respondsToSelector:inSelector] && [self methodForSelector:inSelector] == [super methodForSelector:inSelector] );
}
According to Apple documents you should call respondsToSelector before methodForSelector.
You can use reflection to do that.