Sebastian Wramba
Sebastian Wramba

Reputation: 10127

Mock a class whose methods are invoked in the test case

So I have a class I wrote some test cases for. This class has these two methods:

- (void)showNextNewsItem {
    self.xmlUrl = self.nextNewsUrl;
    [self loadWebViewContent];
}

- (void)showPreviousNewsItem {
    self.xmlUrl = self.previousNewsUrl;
    [self loadWebViewContent];
}

Could be refactored and this is quite primitive, but nevertheless I just want to make sure next loads next and previous loads previous. So I use OCMock to instantiate a OCMockObject for my SUT class like this:

- (void)testShowNextOrPreviousItemShouldReloadWebView {

    id mockSut = [OCMockObject mockForClass:[NewsItemDetailsViewController class]];

    [[[mockSut expect] andReturn:@"http://www.someurl.com"] nextNewsUrl];
    [[mockSut expect] loadWebViewContent];

    [[[mockSut expect] andReturn:@"http://www.someurl.com"] previousNewsUrl];
    [[mockSut expect] loadWebViewContent];

    [mockSut showNextNewsItem];
    [mockSut showPreviousNewsItem];

    [mockSut verify];
}

The problem lies in the two lines actually calling the methods that do something to be verified. OCMock now tells me, that invoking showNextNewsItem and showPreviousNewsItem are not expected. Of course, it's not expected because I am in the test and I only expect certain things to happen in the production code itself.

Which part of the mocking concept didn't I understand properly?

Upvotes: 3

Views: 135

Answers (2)

Sebastian Wramba
Sebastian Wramba

Reputation: 10127

I found the solution. Using a partialMock on the object does exactly what I want. This way, calls I explicitly define are mocked and I call the methods that are under test on the "not-mocked" object.

- (void)testShowNextOrPreviousItemShouldReloadWebView {

    NewsItemDetailsViewController *sut = [[NewsItemDetailsViewController alloc] init];

    id mockSut = [OCMockObject partialMockForObject:sut];

    [[[mockSut expect] andReturn:@"http://www.someurl.com"] nextNewsUrl];
    [[mockSut expect] loadWebViewContent];

    [[[mockSut expect] andReturn:@"http://www.someurl.com"] previousNewsUrl];
    [[mockSut expect] loadWebViewContent];

    [sut showNextNewsItem];
    [sut showPreviousNewsItem];

    [mockSut verify];
}

Upvotes: 2

Don Roby
Don Roby

Reputation: 41127

It's generally confusing to mock the class under test, but if you want to do that, you need a "partial mock", so that you can call methods without stubbing them and have them execute the normal methods.

This appears to be supported in OCMock according to the docs.

Upvotes: 2

Related Questions