Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing pushViewController in Swift

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?

like image 272
Maggy Avatar asked Jun 13 '26 09:06

Maggy


1 Answers

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.

like image 137
Jon Reid Avatar answered Jun 15 '26 23:06

Jon Reid