Question

after a little crash course with OCUnit and OCMock, i have to ask a question. Maybe it´s an easy thing, but i can´t get my head around that.

In this tiny little method:

- (void)setLoginButtonTitleForState:(BOOL)isLoggedIn {

if (isLoggedIn) {

    [_loginButton setTitle:@"Logout" forState:UIControlStateNormal];
}
else {
    [_loginButton setTitle:@"Login" forState:UIControlStateNormal];
}

}

i want to test if the title label is filled correctly. Since i´m learning How to write tests for such cases, i wrote the method before writing tests. But i have to implement the tests anyway.

If there is anybody out there who has done this before, please help me out. This is what i´ve done so far:

- (void)test_checkLoginAndSetLoginButtonAndTitle_loggedIn {
    MyViewController *myViewController = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
    id mock_vc = [OCMockObject partialMockForObject:myViewController];


    UIButton *loginButton = [[UIButton alloc] init];
    id mock_button = [OCMockObject partialMockForObject:loginButton];

    [mock_vc setLoginButton:mock_button];

    [[mock_vc expect] setLoginButtonTitleForState:YES];

    [[mock_button expect] setTitle:@"Logout" forState:UIControlStateNormal];

    [mock_vc verify];
}

So the question is: What am i doing wrong here?

BTW: When i run the test, i get following error:

/Unknown.m: OCPartialMockObject[MyViewController]: expected method was not invoked: setLoginButtonTitleForState:YES

I don´t know why it doesn´t invoke the method as it is public and accessible.

If anyone has hints for me, let me know!

Was it helpful?

Solution

So, maybe this doesn't directly answer your question on your to test [UIButton setTitle:forState:], but I would submit that you shouldn't test a stock Apple API. To test your logic for setting the login button title, I would actually change it so that it returns a string that in a different method will set whatever title on the button. Here's what I mean:

- (void)setLoginButtonTitleForState:(BOOL)isLoggedIn {
  [_loginButton setTitle:[self buttonTitleForLoggedIn:isLoggedIn] forState:UIControlStateNormal];
}

- (NSString *)buttonTitleForLoggedIn:(BOOL)loggedIn {
  return (loggedIn) ? @"Logout" : @"Login";
}

and your test would look something like this:

- (void)test_checkLoginAndSetLoginButtonAndTitle_loggedIn {
    MyViewController *myViewController = [[MyViewController alloc] initWithNibName:@"MyViewController" bundle:nil];
    STAssertEqualObjects([myViewController buttonTitleForLoggedIn:YES], @"Logout", @"After logging in, the 'login' button's title should be set to logout");
}

OTHER TIPS

Don't over-mock everything. Why don't you just check that the correct string was set? That is what you really care about, right (the end result, not how you got there)?

You can get the label from the button and compare that agains the expected value using titleForState:

NSString *actual = [loginButton titleForState:UIControlStateNormal];
STAssertEqualObjects(actual, @"Logout", @"The button should say 'Logout' by now");
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top