3

New in OCMock 3 is the ability to mock out class methods.

Is it possible to mock class methods defined in a protocol? i.e

@protocol AViewControllerProtocol <NSObject>
+ (Type)typeForViewController;
@end

Inside my unit test class

- (void)testProtocolClassMethod {
    id mockedViewController = OCMProtocolMock(@protocol(AViewControllerProtocol));

    //This line compiles fine, but throws an exception at run time.
    OCMStub([mockedViewController typeForViewController]).andReturn(SomeType);
}

Exception throw

NSInvalidArgumentException: cannot stub/expect/verify method 'typeForViewController' because no such method exists in the mocked class

ajmccall
  • 2,024
  • 23
  • 42

1 Answers1

0

This looks like it was an oversight in OCMock 3.1, but you can make the fix yourself, if you want.

// OCProtocolMockObject.m
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    struct objc_method_description methodDescription = protocol_getMethodDescription(mockedProtocol, aSelector, YES, YES);
    if(methodDescription.name == NULL) 
    {
        methodDescription = protocol_getMethodDescription(mockedProtocol, aSelector, NO, YES);
    }
    // Add this case for required class methods
    if (methodDescription.name == NULL)
    {
        methodDescription = protocol_getMethodDescription(mockedProtocol, aSelector, YES, NO);
    }
    // Add this case for optional class methods
    if (methodDescription.name == NULL)
    {
        methodDescription = protocol_getMethodDescription(mockedProtocol, aSelector, NO, NO);
    }
    if(methodDescription.name == NULL)
    {
        return nil;
    }
    return [NSMethodSignature signatureWithObjCTypes:methodDescription.types];
}

I verified this fix with this test:

- (void)testProtocolClassMethod {
    id mockedViewController = OCMProtocolMock(@protocol(AViewControllerProtocol));

    // FIXED: This line compiles fine, but throws an exception at run time.
    OCMStub([mockedViewController typeForViewController]).andReturn(SomeType);

    Type type = [mockedViewController typeForViewController];

    XCTAssertEqual(type, SomeType, @"Not equal!");

    OCMVerify([mockedViewController typeForViewController]);
}

I'll put a request in on the project page for this.

Ben Flynn
  • 18,524
  • 20
  • 97
  • 142