Carlos Maria Caraccia
Carlos Maria Caraccia

Reputation: 500

Unit test, to test if a view controller has presented another view controller

I want to make a unit test to see if a view controller is presenting another view controller.

   func testMainTabController_WhenActionButtonIsTapped_NewSuppliersInvoiceControllerIsCreatedV2() {
        
        let sut = MainTabBarController()
        sut.loadViewIfNeeded()
        let myExpectation = expectation(description: "The sut should present a view controller")
        sut.actionButton.sendActions(for: .touchUpInside)

        if let x = sut.presentedViewController {
            myExpectation.fulfill()
        } else {
            XCTFail("The view controller was not presented")
        }
        
        wait(for: [myExpectation], timeout: 3)
    }

Here the result I obtain is fail test. Because I get nil as a presentedViewController. This is the code of the button

@objc func handleActionButtonTap() {
    let suppliersInvoiceController = SuppliersInvoiceController()
    let navCon = UINavigationController(rootViewController: suppliersInvoiceController)
    navCon.modalPresentationStyle = .fullScreen
    present(navCon, animated: true, completion: nil)
}

This is the code I wrote in the test. The code in the button is successfully called when I run the unit test and the present method is called. Of course if I run the app it works properly. When I tap the button, I get my presented view controller. If I type let vc = presentedViewController inside handleActionButtonTap() and print(vc) I get the nav con as a result. But why can't I do it inside the unit test?

Does anybody has a clue of whats going on?

Thanks

Upvotes: 3

Views: 3531

Answers (2)

Shadowrun
Shadowrun

Reputation: 3857

Does you viewController have enough context for presentViewController:animated: to work? for example, it has no window. PresentViewController:animated: does different things in "horizontally regular environment" etc.

If you want to unit test, how about changing the VC to not present other VC's directly from itself, instead have it call a method on e.g. a coordinator object that you can mock in, then assert that the mock's version of 'present:animated:' gets called as you would expect.

Upvotes: 2

Glenn Posadas
Glenn Posadas

Reputation: 13291

What you want is to do UITest and not UnitTest.

What is a Unit Test? https://x-team.com/blog/how-to-get-started-with-ios-unit-tests-in-swift/

A unit test is a function you write that tests something about your app. A good unit test is small. It tests just one thing in isolation. For example, if your app adds up the total amount of time your user spent doing something, you might write a test to check if this total is correct.


So going back to the answer, do UI Testing for that. Here's a sample cheat sheet for doing UI Tests after a google search: https://github.com/joemasilotti/UI-Testing-Cheat-Sheet

In UI Testing, you will be able to check if a screen was pushed or presented after tapping on a button or something, like for example:

XCTAssert(app.staticTexts["Some Static String From SuppliersInvoiceController "].exists)

Upvotes: 6

Related Questions