Mocking a UIKit Delegate Protocol with Kiwi

I'm experimenting with mock objects in Kiwi and decided to try and mock the UIAlertViewDelegate. I ran into two issues. 1. Order is important when creating the mock delegate object. It needs to be setup with all the delegate method receive calls before you use the object associated with the delegate protocol.

2.  The delegate protocol methods need to be mocked in the order they are invoked, or you'll receive a test failure. This can be trial and error, if you don't know how the delegate protocol works.

a. For each mock delegate test, I just kept running until I was able to get the mock delegate calls passing.

b. I also discovered that the didDismissWithButtonIndex and  clickedButtonAtIndex were not invoked after using the dismissWithClickedButtonIndex method call.

[objc] #import "Kiwi.h" #import "PSMessages.h" #import "PSMessageConstants.h"

SPEC_BEGIN(PSMessagesTest)

describe(@"Create an alertview", ^{ __block PSMessages *messages = nil; beforeEach(^{ messages = [[PSMessages alloc] init]; });

NSDictionary *urlMessage = @{ @"type" : @"url", @"url" : @"http://www.PhotoTableApp.com", @"message" : @"Create a collage for the next holiday.", @"title" : @"Design Collages", @"buttons" : @[@"Yes", @"No"] };

context(@"with a url message", ^{ __block UIAlertView *alert = nil; beforeEach(^{ alert = [messages alertForMessage:urlMessage]; }); it(@"the cancel button is pressed", ^{ id delegateMock = [KWMock mockForProtocol:@protocol(UIAlertViewDelegate)]; alert.delegate = delegateMock;

int buttonIndex = alert.cancelButtonIndex;

[[[delegateMock shouldEventually] receive] alertViewShouldEnableFirstOtherButton:alert]; [[[delegateMock shouldEventually] receive] didPresentAlertView:alert]; [[[delegateMock shouldEventually] receive] willPresentAlertView:alert]; [[[delegateMock shouldEventually] receive] alertView:alert willDismissWithButtonIndex:buttonIndex]; [[[delegateMock shouldEventually] receive] alertView:alert willDismissWithButtonIndex:buttonIndex];

// Note: delegate methods not called for programatic UIAlertView dismiss [[[delegateMock shouldEventually] receive] alertView:alert didDismissWithButtonIndex:buttonIndex]; [[[delegateMock shouldEventually] receive] alertView:alert clickedButtonAtIndex:buttonIndex];

// Invoke methods after the delegateMock object is setup [alert show]; [alert dismissWithClickedButtonIndex:buttonIndex animated:NO];

});

it(@"the ok button is pressed", ^{ id delegateMock = [KWMock mockForProtocol:@protocol(UIAlertViewDelegate)]; alert.delegate = delegateMock;

int buttonIndex = alert.firstOtherButtonIndex;

[[[delegateMock shouldEventually] receive] alertViewShouldEnableFirstOtherButton:alert]; [[[delegateMock shouldEventually] receive] didPresentAlertView:alert]; [[[delegateMock shouldEventually] receive] willPresentAlertView:alert]; [[[delegateMock shouldEventually] receive] alertView:alert willDismissWithButtonIndex:buttonIndex]; [[[delegateMock shouldEventually] receive] alertView:alert willDismissWithButtonIndex:buttonIndex];

// Invoke methods after the delegateMock object is setup [alert show]; [alert dismissWithClickedButtonIndex:buttonIndex animated:NO];

}); });

}); SPEC_END [/objc]