ios - How to unit test a UIViewController - TDD/BDD -
unit testing never seem able head around can see why important , can huge time saver (if know you're doing). hoping can point me in right direction.
i have following uiviewcontroller
qbelectricitybasevc.h
@interface qbelectricitybasevc : qbstatevc @property (nonatomic, strong) qbelectricityusage *electricityusage; @property (nonatomic, assign) cgfloat tabbarheight; - (void)updateelectricityusage; @end
qbelectricitybasevc.m
@implementation qbelectricitybasevc - (instancetype)init { self = [super init]; if (self) { self.tabbaritem = [[uitabbaritem alloc] initwithtitle:nslocalizedstring(@"electricity_title", nil) image:nil tag:0]; } return self; } - (void)viewwillappear:(bool)animated { [super viewwillappear:animated]; [self.notificationcenter addobserver:self selector:@selector(updateelectricityusage) name:kupdatedelectricityusagekey object:nil]; } - (void)viewwilldisappear:(bool)animated { [super viewwilldisappear:animated]; [self.notificationcenter removeobserver:self]; } - (void)updateelectricityusage { self.electricityusage = [self.statemanager electricityusage]; } - (cgfloat)tabbarheight { return self.tabbarcontroller.tabbar.frame.size.height; } @end
what should test?
- an observer
kupdatedelectricityusagekey
added self.electricityusage
becomes instance ofqbelectricityusage
- a
tabbarheight
returned - an observer
kupdatedelectricityusagekey
removed
am missing should test or testing shouldn't?
how test?
so trying using specta , expexta. if need mock using ocmockito.
i don't know how test observer added/removed. see following in expexta documentation not sure if relevant/how use it:
expect(^{ /* code */ }).to.notify(@"notificationname"); passes if given block of code generates nsnotification named notificationname. expect(^{ /* code */ }).to.notify(notification); passes if given block of code generates nsnotification equal passed notification.
to test self.electricityusage
becomes instance of qbelectricityusage
create category has method pretends notification fired , calls updateelectricityusage
method best way?
and tabbarheight
, should test returns valid cgfloat
, not worry value is?
update
i changed viewwillappear
method below:
- (void)viewwillappear:(bool)animated { [super viewwillappear:animated]; [self addnotificationobservers]; } - (void)addnotificationobservers { [self.notificationcenter addobserver:self selector:@selector(updateelectricityusage) name:kupdatedelectricityusagekey object:nil]; }
and created following test:
#import "specs.h" #import "qbelectricitybasevc.h" #import "electricityconstants.h" specbegin(qbelectricitybasevcspec) describe(@"qbelectricitybasevc", ^{ __block qbelectricitybasevc *electricitybasevc; __block nsnotificationcenter *mocknotificationcenter; beforeeach(^{ electricitybasevc = [qbelectricitybasevc new]; mocknotificationcenter = mock([nsnotificationcenter class]); electricitybasevc.notificationcenter = mocknotificationcenter; }); aftereach(^{ electricitybasevc = nil; mocknotificationcenter = nil; }); it(@"should have notification observer updated electricity usage", ^{ [electricitybasevc addnotificationobservers]; [verify(mocknotificationcenter) addobserver:electricitybasevc selector:@selector(updateelectricityusage) name:kupdatedelectricityusagekey object:nil]; }); }); specend
that test passes correct/best way test this?
you've felt 1 big con of ios viewcontrollers: they suck @ testability.
- viewcontrollers mix logic of managing view , model
- this leads massive viewcontrollers
- this violates single responsibility rule
- this makes code not reusable
another big problem mvc discourages developers writing unit tests. since view controllers mix view manipulation logic business logic, separating out components sake of unit testing becomes herculean task. task many ignore in favour of… not testing anything.
maybe should think using mvvm instead. great article explaining difference of ios mvc , mvvm.
the great thing using mvvm can use databinding using reactive cocoa. here's tutorial explain data binding mvvm , reactive programming in ios.
Comments
Post a Comment