4

As I heard before and recently learned in Jon Reid's very good screencast, some init methods or in iOS applications, the viewDidLoad methods tend to get bigger and bigger. I tried to refactor this method:

- (void)viewDidLoad {
    // 10+ lines of setting default property

    // 20+ lines of setting up the navigation bar

    // 20+ lines of resetting the view hierarchy
}

This was replaced by a very nice and short method that contains calls to other methods with speaking names:

- (void)viewDidLoad {
    [super viewDidLoad];

    [self setDefaultResourceNames];
    [self setupRightBarButtonItems];
    [self restoreNavigationControllerHierarchy];

    [[NSNotificationCenter defaultCenter] addObserver: (...)];

}

Now those three methods are now being unit tested, which is much better than before. Now my question is, should the viewDidLoad method be tested as well?

To do this, I made a partial mock out of my class under test and wrote the following test:

- (void)testViewDidLoadShouldInstantiateControllerCorrectly {
    NewsItemDetailsViewController *sut = [[NewsItemDetailsViewController alloc] init];
    id mockSut = [OCMockObject partialMockForObject:sut];
    [[mockSut expect] setDefaultResourceNames];
    [[mockSut expect] setupRightBarButtonItems];
    [[mockSut expect] restoreNavigationControllerHierarchy];

    [mockSut viewDidLoad];

    [mockSut verify];
}

Is this any good? This seems to be largely coupled to actual source code and method execution rather than effects caused by calling the method (which is actually what unit testing is about, as far as I learned). But the effects of calling the method are actually covered in the three unit tests, testing the sub-methods.

Is it good to have this test or is it unnecessary when all other calls are already under test?

Sebastian Wramba
  • 10,087
  • 8
  • 41
  • 58
  • 1
    Don't call `viewDidLoad` directly because that's not what happens in your actual app. Just call `[sut view]` or `[mockSut view]` (not sure which based on this framework). Instantiating the view object will go through all of the view creation methods in the proper order. – Aaron Brager Jan 22 '13 at 20:23

2 Answers2

1

It depends on what you're testing. There's no general solution here; you need to make a decision based on your own professional judgement.

Is it beneficial in this case to test the control flow, or to provide a regression safety net for it? Do the benefits outweigh the cost?

Mocking for the sake of consistency is largely discouraged. It has been proven harmful in most cases. Use it as a tool, where you actually need it.

Yam Marcovic
  • 7,953
  • 1
  • 28
  • 38
  • So what you're saying is: If I want to make sure, the initializing method does exactly this and nothing else, I should test it by mocking it like this? What do you mean by "for the sake of consistency"? When should I NOT mock something? – Sebastian Wramba Jan 20 '13 at 17:35
  • When you gain nothing from it. Mocking was first introduced as a tool to help testing classes in isolation from IO and side effects. Then the notion conceived that you should also test control flow in the background - but in practice the costs of doing that outweigh the benefits. – Yam Marcovic Jan 20 '13 at 21:51
1

This is a perfectly reasonable approach. You want to test two types of things: 1) things you don't want to break, and 2) things you want to document. If this approach fits either or both of those criteria for you it's fine.

I think the main drawback of tests like this is that they can add a lot of coding overhead to something that is self-evident. View setup code is often very readable--you can scan through it and understand what's going on, so the tests don't add much documentation value. And if the view is one you use every time you use the app, it may be immediately clear when you do QA if any of the view setup is broken, so the tests don't add much defensive coding value.

In the end, you're the one who will maintain this code and be responsible for fixing it when it breaks, so it's up to you to determine whether the testing effort now outweighs the risks later.

Christopher Pickslay
  • 17,523
  • 6
  • 79
  • 92