Slide 1

Slide 1 text

Practical examples of using stubs and mocks in unit tests Victor Ilyukevich @yas375

Slide 2

Slide 2 text

– Martin Fowler “There is a difference in that the stub uses state verification while the mock uses behavior verification.” http://martinfowler.com/articles/mocksArentStubs.html

Slide 3

Slide 3 text

Stubs • Stubs drive the production code through different paths by returning predefined values in response to method calls from SUT (System Under Test). • You verify state of your SUT.

Slide 4

Slide 4 text

enabledRemoteNotificationTypes it(@"is Allowed", ^{ id value = theValue(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound); ! UIApplication *app = [UIApplication sharedApplication]; [app stub:@selector(enabledRemoteNotificationTypes) andReturn:value]; ! [[theValue(manager.status) should] equal:theValue(CZAllowed)]; });

Slide 5

Slide 5 text

Current date context(@"when current minute is 44", ^{ it(@"creates an event that starts on the next hour", ^{ NSDate *fakeNow = [NSDate dateFromYear:2012 month:1 day:14 hour:14 minute:44]; [NSDate stub:@selector(date) andReturn:fakeNow]; ! [event setupDefaultValues]; ! [[event.startsAt should] equal:[NSDate dateFromYear:2012 month:8 day:23 hour:15 minute:00]]; }); });

Slide 6

Slide 6 text

NSCalendar context(@"when recurs on Sunday, Monday, Tuesday and Friday", ^{ ! it(@"returns 'Sun, Mon, Tue, Fri'", ^{ [[reminder.displayShortRecurrenceDays should] equal:@"Sun, Mon, Tue, Fri"]; }); ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! }); });

Slide 7

Slide 7 text

NSCalendar context(@"when recurs on Sunday, Monday, Tuesday and Friday", ^{ context(@"in US", ^{ it(@"returns 'Sun, Mon, Tue, Fri'", ^{ [[reminder.displayShortRecurrenceDays should] equal:@"Sun, Mon, Tue, Fri"]; }); }); ! context(@"in Russia", ^{ beforeEach(^{ NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; calendar.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"ru_RU"]; calendar.firstWeekday = 2; ! [NSCalendar stub:@selector(currentCalendar) andReturn:calendar]; }); ! it(@"returns 'Пон, Вт, Пт, Вск'", ^{ [[reminder.displayShortRecurrenceDays should] equal:@"пн, вт, пт, вс"]; }); }); });

Slide 8

Slide 8 text

Mocks • Behaviour verification, not state. • Mock know what should happen. • You verify that SUT behaves as expected, i.e. calls a method on a mock. • The tests ask the mock if everything went as expected.

Slide 9

Slide 9 text

sharedInstance it(@"tracks 'Item viewed’ on appearing", ^{ KWMock *analytics = [KWMock nullMockForClass:[Analytics class]]; [Analytics stub:@selector(sharedInstance) andReturn:analytics]; ! [analytics should] receive:@selector(track:properties:) withArguments:@"Item viewed", @{ @"Type": @"Calendar event" }, nil]; ! TriggerViewAppearing(controller); });

Slide 10

Slide 10 text

A crazy example of spying* it(@"shows alert 'Can't do this...'", ^{ KWMock *notInitializedAlert = [KWMock nullMockForClass:[UIAlertView class]]; KWCaptureSpy *spy = [notInitializedAlert captureArgument:@selector(initWithTitle: message: delegate: cancelButtonTitle: otherButtonTitles:) atIndex:1]; ! [UIAlertView stub:@selector(alloc) andReturn:notInitializedAlert]; ! [subject showUnableToShareAlertIfNeeded]; ! [[spy.argument should] equal:@"Can't do this right now..."]; });

Slide 11

Slide 11 text

Thanks Victor Ilyukevich @yas375