iosswiftunit-testinguiviewcontrolleruikit

What is the correct approach of Unit Testing in iOS?


class RemoveMyDataConsentFormVCTests: XCTestCase {
    var viewController: RemoveMyDataConsentFormVC!

    override func setUp() {
        super.setUp()
        
        let storyboard = UIStoryboard(name: "RemoveMyDataConsentForm", bundle: nil) // Replace "Main" with your storyboard name
        viewController = storyboard.instantiateViewController(withIdentifier: "RemoveMyDataConsentFormVC") as? RemoveMyDataConsentFormVC
        viewController.loadViewIfNeeded()
    }

    override func tearDown() {
        viewController = nil
        super.tearDown()
    }
    
    func testSetupTextFields() {
        if viewController.emailTextField.text == "" {
            viewController.emailTextField.text = nil
        }
                
        XCTAssertNotNil(viewController.emailTextField.text, "Error for email should be hidden")
        XCTAssertTrue((viewController.errorForStates != nil), "Error for email should be hidden")
        XCTAssertTrue((viewController.errorForCountries != nil), "Error for email should be hidden")
        XCTAssertTrue((viewController.errorForLastName != nil), "Error for email should be hidden")
        XCTAssertTrue((viewController.errorForFirstName != nil), "Error for email should be hidden")
    }
}

Above is my code for my UIViewController for which I have written a unit test to setup text fields. I am looking for an example to improve the way I write unit tests using Swift 5.

The test is passing, but it didn’t seem to be a good practice to write the unit test the correct way.


Solution

  • There are two common types of tests:

    To this end, many of us try to abstract the business logic out of the view layer (i.e., we pull it out of the view controller, for example). Different teams/projects use different techniques/terminology to accomplish this: Some use “view models”. Some use “presentation” objects. Some use more abstract “controller” (not to the confused with UI-specific “view controller”) or “service” objects to encapsulate this business logic.

    Regardless of how one approaches this, the idea is that for testability reasons (as well as just general good design) we abstract business logic out of the UI layer of our codebase (i.e., we pull this out of the view controllers). We then write “unit tests” to validate these business logic functions/objects, completely separate from any UI code. We then write “UI tests” to verify that our UI behaves the way we expected, not to verify the internal state of the view layer.


    See the distinction between unit tests a UI tests about 1:33 into WWDC 2023’s Fix failures faster with Xcode test reports:

    enter image description here