iosiphoneobjective-cocmock

OCMock - partial mocking [UIAlertView alloc]


I'm having an issue with the OCMock framework for iOS. I'm essentially trying to mock UIAlertView's initWithTitle:message:delegate... method. The example below doesn't work in the sense that the stubbed return value isn't returned when I call the initWithTitle method.

UIAlertView *emptyAlert = [UIAlertView new];
id mockAlert = [OCMockObject partialMockForObject:[UIAlertView alloc]];
[[[mockAlert stub] andReturn:emptyAlert] initWithTitle:OCMOCK_ANY message:OCMOCK_ANY delegate:nil cancelButtonTitle:OCMOCK_ANY otherButtonTitles:nil];

UIAlertView *testAlertReturnValue = [[UIAlertView alloc] initWithTitle:@"title" message:@"message" delegate:nil cancelButtonTitle:@"ok" otherButtonTitles:nil];
if(testAlertReturnValue == emptyAlert) {
    NSLog(@"UIAlertView test worked");
}

However, it does work if I use the same idea for NSDictionary.

NSDictionary *emptyDictionary = [NSDictionary new];
id mockDictionary = [OCMockObject partialMockForObject:[NSDictionary alloc]];
[[[mockDictionary stub] andReturn:emptyDictionary] initWithContentsOfFile:OCMOCK_ANY];

NSDictionary *testDictionaryReturnValue = [[NSDictionary alloc] initWithContentsOfFile:@"test"];
if(testDictionaryReturnValue == emptyDictionary) {
    NSLog(@"NSDictionary test worked");
}

One thing I notice is that the method "forwardInvocationForRealObject:" in "OCPartialMockObject.m" is called during the NSDictionary initWithContentsOfFile call, but not during the UIAlertView initWithTitle call.

Could this be an OCMock bug?


Solution

  • I had issues with mocking UIAlertView as well, and my best guess is that it's the vararg that's throwing it off (can't 100% remember though). My solution was to create a factory method for UIAlertView and add it as a category.

    + (instancetype)alertViewWithTitle:(NSString *)title message:(NSString *)message delegate:(id)delegate cancelButtonTitle:(NSString *)cancelButtonTitle otherButtonTitles:(NSArray *)otherButtonTitles;
    

    Notice that I replace the varargs with an NSArray. This method is definitely mockable, and the syntax is pretty similar now that we have array literals:

    [UIAlertView alertViewWithTitle:@"Warning" message:@"Really delete your save file?" delegate:self cancelButtonTitle:@"No" otherButtonTitles:@[ @"Yes", @"Maybe" ]];
    

    If you have the flexibility to change your source code, this'd be my suggestion.

    EDIT

    Looking more closely at your code, you are creating a partial mock, stubbing it's init method, then not doing anything with it. It's possible the way you are doing it might actually work if you replace the [UIAlertView alloc] with the mock you create. Can't say for sure because I do remember having issues with it.