Unit Testing View Controllers


#1

Hi guys, have anyone of you tried unit testing a view controller where a view controller needs to present something like alerts or a new view controller.

Currently I am trying to test if my view controller shows an alert after present an alert controller. But when I accessed the view controller’s isPresentingViewController, presentedViewController. It always return nil

Here’s my snippet code:

  func testForNoConnectionState() {
    let _ = createUsernameVC.view
    let observableExpectation = expectation(description: "Observable Expectation")
    createUsernameVC.viewModel.output.viewControllerState.asObservable().subscribe(onNext: { (state) in
      XCTAssertEqual(state, CreateUsernameViewControllerState.noConnection)
      observableExpectation.fulfill()
    }).disposed(by: disposeBag)
    createUsernameVC.viewModel.output.viewControllerState.onNext(.noConnection)
    XCTAssertNotNil(createUsernameVC.presentedViewController)
    XCTAssertEqual((createUsernameVC.presentedViewController as! UIAlertController).title, "No connection")
    XCTAssertEqual((createUsernameVC.presentedViewController as! UIAlertController).message, "Please connect to the internet")
  }

#2

This test fails by the way because presentedViewController always returns nil.


#3

How did you present the View controller? About presentedViewController

If the current view controller did not present another view controller modally, the value in this property is nil .


#4

I do not use the unit testing when it involves the UI. You may want to consider doing VC tests using the UI test framework.

My test is organized like below:
UI Tests - integration, UI tests, would use mock or real services
Unit Tests - not UI code and usually would use only fake/mocks


#5

Haven’t tested this but you may need to add your view controller to a UIWindow:

Source:

beforeEach {
  let window = UIWindow(frame: UIScreen.main.bounds)
  window.makeKeyAndVisible()
  window.rootViewController = vc
  _ = vc.view
}

It’s using Quick syntax but that’s basically you’re setUp() method on XCTest. For some UIView/UIViewController properties, you need to add them to a UIWindow before they work ex.(firstResponder: https://clean-swift.com/testing-view-controller-part-2/)

For me, I’m not sure about RXSwift testing (I’m sure there’s a specialized library for that )but I would just probably check a Mock that receives the no connection event for a unit test. and just assert the presented view controller on a UI test. Although that’s probably a more difficult set-up.

ex.

XCTAssert(ViewModelOutputMock.receivedNoConnectionEvent == true)