0

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

JeremyP
  • 84,577
  • 15
  • 123
  • 161
  • You have made a mock of your controller in `mock` but you are still operating on your `controller` they are two different objects. – Paul.s Dec 12 '11 at 11:25
  • Thanks Paul. I'm a still a little confused though & am hoping you might be able to elaborate because if they're two different objects, I don't understand why the controller viewedPages count matches the (new) count I set for the Mock object? Without creating the mock, I have two records. When I mock the object and swizzle the loadViewedPages method, the controller and the mock both show three records which surprises me if they're different objects. Again, this will most definitely be down to a misunderstanding on my part and the documentation I've found hasn't helped me. Cheers! – Shane Henderson Dec 12 '11 at 14:25
  • I've just tried the following, but still the same results `[mock viewDidLoad]; NSLog(@"%d", [[mock pageControl] numberOfPages]); NSLog(@"%d", [[mock chefs] count]);` Really confused about this and appreciate any help – Shane Henderson Dec 12 '11 at 14:34

1 Answers1

1

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];
}
Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92
  • Thank you very much - this is exactly the approach I took in the very early hours of the morning to get the test passing! However, I also managed to finally get the test running using the STAssertTrue (as in the original method I posted) as well. To achieve that, I created a local instance of a UIPageControl in the test function, and stubbed the controller to use the local PageControl instead of the one in the controller. All counts tallied correctly once I had that. (I had been trying to swap it with an OCMock version, but turns out I just had to create a genuine local one!) – Shane Henderson Dec 13 '11 at 03:44