Benjamin Toueg
Benjamin Toueg

Reputation: 10867

UnitTests and iOS : viewDidLoad triggered twice

I am testing the viewDidLoad event on one of my UIViewController.

- (void)testMyView
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
    MyViewController *vc = [storyboard instantiateViewControllerWithIdentifier:MYID];
    [vc viewDidLoad];

    STAssertNotNil(vc, @"MyViewController should not be nil");
}

If I remove the line [vc viewDidLoad];, the viewDidLoad is never triggered.

If I let [vc viewDidLoad]; in place, the viewDidLoad is triggered twice.

I understand that views are lazy loaded, but how can I avoid that behavior?

Is there any best practice regarding View testing?

Upvotes: 1

Views: 2769

Answers (5)

JERC
JERC

Reputation: 1624

You can only use the following call to execute the viewDidLoad only once:

_ = vc.view

Upvotes: 0

onmyway133
onmyway133

Reputation: 48095

Read my note https://github.com/onmyway133/blog/issues/52

Suppose we have the following view controller

class ListController: UIViewController {
  override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .white
  }
}

Get to know viewDidLoad

We know that viewDidLoad is called when view is created the first time. So in the the Unit Test, if you use viewDidLoad to trigger, you will fall into a trap

func testSetup() {
  let controller = ListController()
  controller.viewDidLoad()
}

Why is viewDidLoad called twice?

It is called once in your test And in your viewDidLoad method, you access view, which is created the first time, hence it will trigger viewDidLoad again

The correct way

The best practice is not to trigger events yourself, but do something to make event happen. In Unit Test, we just access view to trigger viewDidLoad

func testSetup() {
  let controller = ListController()
  let _ = controller.view
}

Upvotes: 1

danielhadar
danielhadar

Reputation: 2161

Call layoutIfNeeded() on the view controller's view, namely:

[vc.view layoutIfNeeded]

Upvotes: 0

Sumit Kumar Saha
Sumit Kumar Saha

Reputation: 799

Do lazy loading using [vc view];

Upvotes: 0

lnafziger
lnafziger

Reputation: 25740

You need to access the view in order to have it load automatically.

You can use something like this to do it without side effects:

vc.view.hidden = NO; // Or YES if it is supposed to be hidden.

Oh, and then remove your manual call to viewDidLoad as it won't be needed.

Upvotes: 11

Related Questions