2

I've been trying to mock a simple property on UITextField:

@property(nonatomic,readonly,getter=isEditing) BOOL editing;

I've tried to mock this 2 ways

1.) using the full blown class method swizzle technique (usually for class based methods I'll do this)

- (void)swapOutTextFieldIsEditing
{
    method_exchangeImplementations(
            class_getClassMethod([UITextField class], @selector(isEditing)),
            class_getClassMethod([self class], @selector(isEditingEnabledMock))
    );
}

- (void)resetTextFieldIsEditing
{
    method_exchangeImplementations(
            class_getClassMethod([self class], @selector(isEditingEnabledMock)),
            class_getClassMethod([UITextField class], @selector(isEditing))
    );
}

+ (BOOL)isEditingEnabledMock {
    return isEditingMockResult;
}

2.) using a custom ocmock helper to create a custom "and return bool" method

 - (id)andReturnBool:(BOOL)aValue {
     NSValue *wrappedValue = nil;
     wrappedValue = [NSValue valueWithBytes:&aValue
                                   objCType:@encode(BOOL)];

     return [self andReturnValue:wrappedValue]; 
}

Sadly both techniques failed and I'm almost sure it's because this is a normal property on UITextField marked readonly w/ a getter (never seen this before on iOS)

**by failed the following NSLog always returns (null) -meaning I can't stub this

- (IBAction)next
{
    for (int i = 0; i<[self.fieldsArray count]; i++) {
        NSLog(@"is this field being edited? %@", [[self.fieldsArray objectAtIndex:i] isEditing]);
    }
}

Here is my basic stub syntax (used w/ the above)

id firstField = [OCMockObject niceMockForClass:[UITextField class]];
[[[firstField stub] andReturnBool:YES] isEditing];

Does anyone know of another way to stub this result? If not what about the 2 approaches listed above? Anything I'm doing incorrectly here?

Thank you in advance

Stunner
  • 12,025
  • 12
  • 86
  • 145
Toran Billups
  • 27,111
  • 40
  • 155
  • 268

2 Answers2

1

You seem to be confusing class methods with instance methods. The runtime function class_getClassMethod returns a class method, but since the method you're interested in is a property accessor, it can't be a class method (classes don't have properties, only instances do). Instead, use class_getInstanceMethod to get the accessor method.

jlehr
  • 15,557
  • 5
  • 43
  • 45
  • well put -yet when I modify this to be class_getInstanceMethod it still doesn't seem to stub this in correctly. any other reason this readonly getter won't let me stub it? – Toran Billups Jun 11 '12 at 01:01
1

When you use this stub setup

id firstField = [OCMockObject niceMockForClass:[UITextField class]];
[[[firstField stub] andReturnBool:YES] isEditing];

what else are you doing with firstField? Are you sure that other objects interact with firstField, the mock instance, or do they interact with a real instance of UITextField that's instantiated in a XIB file?

For the case where you can't inject a mock and you have to do with an instance created elsewhere OCMock provides partial mocks. These allow you to stub methods on existing objects. In you case you could do something like this:

id firstField = ... // somehow get a reference to the actual field object
id firstFieldMock = [OCMockObject partialMockForObject:firstField];
[[[firstFieldMock stub] andReturnBool:YES] isEditing];

After that, when another object calls isEditing on firstField the mock will intercept it.

Erik Doernenburg
  • 2,933
  • 18
  • 21