3

I´ve tried to setup a router for navigating to the right Viewcontroller. When I call this in the simulator, it does work fine.

BUT: When I try to test the outcome of this transition via the topViewController or presentedViewController property of my NavigationController, I always get every Viewcontroller but not the correct one.

My Method looks like the following:

func navigateToViewController(_ viewController: UIViewController, animated: Bool) {
    self.pushViewController(viewController, animated: animated)
}

As I said. It works perfectly fine in the Simulator but I´d like to test it. Every time I call this the ViewController is correctly set. But the result of the Test is a completely different Controller.

When I assert that the topViewController or presentedViewController should be a HomeViewController, I always get a different ViewController as result.

XCTAssertTrue(self.sut.topViewController is HomeViewController,
                   "The TopViewController should be set to the HomeViewController but instead: \(self.sut.topViewController)")

How could that be and how can I solve this?

mfaani
  • 33,269
  • 19
  • 164
  • 293
Maggy
  • 331
  • 4
  • 15
  • Do you want a unit test, or a UI test? – Jon Reid Nov 22 '16 at 02:58
  • It should be a unit test for my router. So that everything is correct including the presented ViewController. – Maggy Nov 22 '16 at 08:01
  • It looks like your class is a subclass or extension of NavigationController. Could you share a little more of its interface? – Jon Reid Dec 10 '16 at 19:04
  • Nope. The Instance of the Controller is the same. That´s why I don´t understand why it´s not working. In the NavigationViewController is nothing more than a switch based on a String to prepare the ViewController which will be passed to the "navigateToViewController" method. – Maggy Jan 03 '17 at 10:49
  • Here I got a Sample Project with just the parts where the Problem occurs. Hope someone can help me about this Issue. https://github.com/Evil-Me/SegueUnitTestApp – Maggy Jan 03 '17 at 14:32

2 Answers2

4

Updated answer:

Use https://github.com/jonreid/ViewControllerPresentationSpy

Original answer:

There doesn't seem to be a good way to unit test the effects of calling performSegue. What we can do instead is record how it was called. In the test code, add this:

fileprivate var performSegueIdentifiers: [String] = []

extension ViewController {
    override open func performSegue(withIdentifier identifier: String, sender: Any?) {
        performSegueIdentifiers.append(identifier)
     }
}

This changes ViewController's performSegue. Instead of actually performing the segue, we append the identifier to performSegueIdentifiers. Since this is file scoped, we need to be careful not to let it "bleed" into other tests. So reset it in setUp:

    override func setUp() {
        super.setUp()
        performSegueIdentifiers = []
        // other set-up
    }

Now your tests can invoke test the contents of this array to determine:

  • The number of times performSegue was called
  • What segue identifiers were passed to it

We can trust that the actual performSegue works. All we need to test is that the production code called it correctly.

Jon Reid
  • 20,545
  • 2
  • 64
  • 95
  • Thanks Jon for your response. I'll try this directly tomorrow morning. Sounds good so far. Many many thanks for your help. I appreciate this. – Maggy Jan 04 '17 at 22:45
  • Jon you are my hero. It worked like a charm. I now can see what segue was performed and can check this. Thanks a lot. – Maggy Jan 10 '17 at 19:08
0

try this code, it will help you get the class name of each view controller in the navigation controller's view controllers stack

for VC in (self.navigationController?.viewControllers)! {
            print(VC.classForCoder)
        }

because I'm not sure what else you have in your code that have possibly added some view controllers to your navigation controller's view controllers stack

Sameh Salama
  • 765
  • 1
  • 7
  • 17