How to write unit test for testing view controller?

2.8k views Asked by At

We are trying to write our custom unit tests for testing every view controller separately. I know there are UI automation, KIF, and other solutions, however if you would take a look at the code above then you will find it should be possible to do it without using them.

So, for the simplicity, suppose there's a simple view controller with two public methods "setFirstState" and "setSecondState". I need to test, is "setFirstState" method called when view controller is fully instantiated and shown on screen (goes through viewDidLoad). Here's demo view controller:

@interface MyViewController 

  - (void)setFirstState;
  - (void)setSecondState;

@end

@implementation MyViewController

  - (void)viewDidLoad {

    [super viewDidLoad];

    [self setFirstState];
  }

@end

So, a unit test for testing setFirstState call could look like (using XCTest and OCMock):

- (void)test_viewDidLoad_CallsMyMethod {

  MyViewController *viewContoller = [[MyViewController alloc] init];

  id mock = [OCMockObject partialMockForObject:viewContoller];
  [[mock expect] showLogin];

  [UIApplication sharedApplication].keyWindow.rootViewController = (MyViewController *)mock;

  [mock verify];
}

The interesting code line is the one assigning mock (on viewController) to keyWindow's rootViewController. We found we need to do that if we want the methods viewDidLoad, viewWillAppear to be called. Otherwise they won't be called. However if we run tests then simulator hangs on this line. Xcode shows it's running and is still alive but it doesn't go further.

We also tried replacing keyWindow's rootViewController code line to "[mock viewDidLoad]" just for simulating and testing viewDidLoad, but it also hangs. So, it looks like partial mock breaks internal flow of appearing view controller.

If we will remove mock and assign view controller directly to keyWindow's rootViewController then it works and we can test all other things. However, maybe anybody have an idea how we could fix that?

UPDATE Forgot to mention we use Xibs instead of Storyboards, so every component in our system is loosely coupled.

1

There are 1 answers

0
Centurion On

It turns out NewRelic library was breaking OCMock :). Therefore everything works after commenting it out:

//[NewRelicAgent startWithApplicationToken:@"token"];