Search code examples
objective-ciosocunitocmock

OCUnit application testing: Trying to test UIPageControl numberOfPages == NSArray count


I'm relatively new to OCUnit and OCMock so please bear with me. I have a view controller which contains a UIPageControl where the number of pages is calculated from the count of an NSArray (which is populated from Core Data). This is done in the ViewDidLoad method as follows:

- (void)ViewDidLoad {
    [super viewDidLoad];

    ... other code ...

    self.pageControl.numberOfPages = [self.viewedPages count];
    self.pageControl.currentPage = 0;

    NSLog(@"%d", controller.pageControl.numberOfPages);
    NSLog(@"%d", [controller.viewedPages count]);
}

The log displays matching integer values for both viewedPages and numberOfPages, and thankfully if I run the below test the assertion is true:

- (void)testPageControl {
    [controller viewDidLoad];
    STAssertTrue(controller.pageControl.numberOfPages == [controller.viewedPages count], @"...");
}

However, as mentioned, this process relies on using an array with objects from Core Data, so I decided to try my hand at OCMock to substitute this with a pre-prefined array to effectively remove the Core Data element. In doing so, I'm now getting results I don't understand.

Here is what my new test looks like:

- (void)testPageControl {
    id mock = [OCMockObject partialMockForObject:controller];
    NSArray *mockPagesArray = [NSArray alloc] initWithObjects:...];
    [[[mock stub] andReturn:mockPagesArray] viewedPages];

    [controller viewDidLoad];

    NSLog(@"%d", [controller.pageControl numberOfPages]);
    NSLog(@"%d", [controller.viewedPages count]);
    STAssertTrue(controller.pageControl.numberOfPages == [controller.viewedPages count], @"...");
    [mockPagesArray release];
}

What is confusing me is that in this scenarios the NSLog shows that the viewedPages count matches the count of the mock array I created (great!) but the numberOfPages is always zero? As a result, the test fails.

I also tried swizzling the function which loads the viewedPages array in the controller, with a local function in the test controller which returns a pre-defined array, i.e.,

[[[mock stub] andCall:@selector(createMockPageViews) onObject:self] loadPageViews];

However, this had exactly the same result as above. The test still fails because the numberOfPages returns 0, whilst the viewedPages array shows the expected count.

As I said, I'm new to OCUnit and OCMock, so I hope this question is as detailed as possible and makes sense. I'm hoping this is down to a misunderstanding on my part on how OCMock works which someone can correct me on - I'll be eternally grateful! There seems to be a real lack of decent documentation out there on OCUnit and OCMock for iPhone development for beginners to learn from unfortunately and this little problem has been driving me mad for two days now...

Thank you in advance


Solution

  • Your controller.pageControl is most likely nil. This could be because it isn't wired to an IBOutlet or otherwise initialized, or because your unit tests aren't actually running within the app executable. Take a look at the steps in setting up your unit test target and check your settings.

    Alternatively, you could mock the UIPageControl object:

    - (void)testPageControl {
        id mockPageControl = [OCMockObject mockForClass:[UIPageControl class]];
        [[mockPageControl expect] setNumberOfPages:3];
        [[mockPageControl expect] setCurrentPage:0];
    
        id mock = [OCMockObject partialMockForObject:controller];
        NSArray *mockPagesArray = [NSArray alloc] initWithObjects:...];
        [[[mock stub] andReturn:mockPagesArray] viewedPages];
        [[[mock stub] andReturn:mockPageControl] pageControl];
    
        [controller viewDidLoad];
    
        [mockPageControl verify];
    }