7

Activating ViewDidAppear in UnitTest:

Before getting to my question, I know there is a question very similar to this one (Unit tests don't call viewDidAppear method) but it doesn't seem quite to answer this.

I am wondering how best to activate viewDidAppear() on a viewController to test various things that should occur in that method. I am pretty sure that it is poor practice to call viewDidAppear() directly; so I am wondering how to call it indirectly in a test.

I have followed Natasha's tutorial https://www.natashatherobot.com/ios-testing-view-controllers-swift/ and so have discovered how to activate viewDidLoad() without needing to call it directly. Near the bottom there is discussion of using beginAppearanceTransition(true, animated: true) to call it indirectly, but this does not seem to be having the expected outcome for me.

Any advice? Thanks!

Community
  • 1
  • 1
EndersJeesh
  • 427
  • 1
  • 4
  • 20

3 Answers3

25

You should call beginAppearanceTransition first for viewWillAppear, and then endAppearanceTransition for viewDidAppear. endAppearanceTransition alone will not execute viewDidAppear:

Swift

 sut.beginAppearanceTransition(true, animated: true)
 sut.endAppearanceTransition()

Objective - C

[self.sut beginAppearanceTransition:YES animated:NO];
[self.sut endAppearanceTransition];
Vojkan Spasic
  • 249
  • 3
  • 3
8

I don't think it's poor practice at all to call viewDidAppear(false) directly for unit testing. I've done so in hundreds of unit tests with no ill effects. After all, viewDidAppear, viewWillAppear and the other lifecycle methods are just that. Methods.

However, I know it's scary to set up view hierarchy for unit tests. With each iOS release, it's uncertain what changes Apple will make to private implementation that may break your view controller tests. But thus far, the only caveat I've seen is sometimes you have to add a controller's view to a window, especially when testing presenting controllers.

I also call loadView() and viewDidLoad() directly. I usually invoke these two methods in the setup portion of a view controller unit test. This prevents me from setting up a complex view controller hierarchy and thus, allows me to test each view controller as a unit.

Calling these methods directly in production code, on the other hand, is poor practice and should be avoided.

David Nix
  • 3,324
  • 3
  • 32
  • 51
  • Can you explain what you mean by "sometimes you have to add a controller's view to a window"? Do you have example code? I've tried setting the window's rootViewController to my view controller, but I still am not successful in calling viewDidAppear on my view controller. – Mike Taverne Jun 27 '17 at 23:17
  • Nevermind! I'm a dope. It is calling my viewDidAppear now, but the condition I was expecting to happen didn't. That's why we unit test, I guess. – Mike Taverne Jun 27 '17 at 23:23
0

Given they are lifecycle methods, why not use an integration style test (UI Test) and possibly look to move any logic/setup code into another class or method that easier to access and test. This keeps viewDidLoad content to a minimum, maybe just containing another method call

MikeJ
  • 2,367
  • 3
  • 18
  • 23