xctest - how to test if a new view loads on a button press
ios, mocking, xctest
Solution
You need an interaction test — that is, a test that checks interactions between objects. In this case, you want to test that `-pushViewController:animated:` is called on the navigation controller with a `SettingsViewController`. So we want to put a mock object into `self.navigationController` which we can ask, "Were you called as expected?"
I'll assume a simple name for the class: MyView.
The way I'd do this by hand is to Subclass and Override `navigationController`. So in my test code, I'd do something like this:
@interface TestableMyView : MyView
@property (nonatomic, strong) id mockNavigationController;
@end
@implementation TestableMyView
- (UINavigationController *)navigationController
{
return mockNavigationController;
}
@end
Now instead of creating a MyView, the test will create a TestableMyView and set its `mockNavigationController` property.
This mock can be anything, as long as it responds to `-pushViewController:animated:` and records the arguments. Here's a simple example, by hand:
@interface MockNavigationController : NSObject
@property (nonatomic) int pushViewControllerCount;
@property (nonatomic, strong) UIViewController *pushedViewController;
@property (nonatomic) BOOL wasPushViewControllerAnimated;
@end
@implementation MockNavigationController
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
self.pushViewControllerCount += 1;
self.pushedViewController = viewController;
self.wasPushViewControllerAnimated = animated;
}
@end
Finally, here's a test:
- (void)testOnSettingsButton_ShouldPushSettingsViewController
{
// given
MockNavigationController *mockNav = [[MockNavigationController alloc] init];
TestableMyView *sut = [[TestableMyView alloc] init];
sut.mockNavigationController = mockNav;
// when
[sut onSettingsButton];
// then
XCTAssertEquals(1, mockNav.pushViewControllerCount);
XCTAssertTrue([mockNav.pushedViewController isKindOfClass:[SettingsViewController class]]);
}
These things can be simplified by using mock object frameworks such as OCMock, OCMockito, or Kiwi's mocking. But I think it helps to start by hand first, so that you understand the concepts. Then choose the tools that help. And if you know how to do it by hand, you'll never say, "Mocking framework X doesn't do what I need! I'm stuck!"
Problem
Just started xcode 5 and xctest. How do I test that a view loads on button press. I have programatically added method that gets called when the rightBarButtonItem is clicked ``` action:@selector(onSettingsButton) ``` and in onSettingsButton ``` -(void) onSettingsButton{ SettingsViewController *svc = [[SettingsViewController alloc] init]; [self.navigationController pushViewController:svc animated:YES]; } ``` How to write xctest to ensure SettingsViewController brings up the Settings view? Thank you.