Search code examples
iosswiftxcodeunit-testingxctestcase

How can we write Unit Test Case for the function in swift ios


I want to write a unit test case for the method which is one of the delegate methods in the view controller. I created a unit test case class for the VC and am trying to write a unit test for the method.

Here is the method which is implemented in VC. How can we write Unit Test Case?

extension DownloadBaseViewController:EMPDecisionTreeCoordinatorDelegate {
    func decisionEmptyTreeFeedbackButtonTapped() {
        if let feedbackNavVc = storyboard?.instantiateViewController(identifier: "PremiumFeedbackNavViewController") as? PremiumCustomNavigationController {
            if let feedbackVc = feedbackNavVc.children.first as? PremiumFeedbackViewController {
                feedbackVc.id = self.fileDetails?.id
                self.decesiontreeCoordinator!.rootViewController.present(feedbackNavVc, animated: true, completion: nil)
            }
        }
    }
}

Created a unit test class for VC and tried not able to write it properly followed few tutorials not found for delegate method.

import XCTest


class DownloadBaseViewControllerTests: XCTestCase {
   
   var downloadBaseViewController: DownloadBaseViewController!
   
   func testDecisionEmptyTreeFeedbackButtonTapped() throws { 
       let feedbackVCNavigation = downloadBaseViewController.decisionEmptyTreeFeedbackButtonTapped
       XCTAssertNotNil(feedbackVCNavigation, "Download base view controller contains feedback view controller and succesfully able to navigate")
 
 ///Test case Build succeded but this is not the way to test it properly need heads up on this.
   }

   override func setUpWithError() throws {
       // Put setup code here. This method is called before the invocation of each test method in the class.
   }
}


Solution

  • Refactor the DownloadBaseViewController in your app so you can mock the dependency:

    extension DownloadBaseViewController:EMPDecisionTreeCoordinatorDelegate {
        // Add this variable in DownloadBaseViewController
        lazy var presentingController: ViewControllerPresenting? = self.decesiontreeCoordinator?.rootViewController
    
        func decisionEmptyTreeFeedbackButtonTapped() {
            if let feedbackNavVc = storyboard?.instantiateViewController(identifier: "PremiumFeedbackNavViewController") as? PremiumCustomNavigationController {
                if let feedbackVc = feedbackNavVc.children.first as? PremiumFeedbackViewController {
                    feedbackVc.id = self.fileDetails?.id
                    self.presentingController?.present(feedbackNavVc, animated: true, completion: nil)
                }
            }
        }
    }
    
     // You need this to mock the foreign dependency on UIViewController 
     protocol ViewControllerPresenting: AnyObject {
        func present(_ viewControllerToPresent: UIViewController,
                     animated flag: Bool,
                     completion: (() -> Void)?)
    }
    
    extension UIViewController: ViewControllerPresenting {}
    

    In the tests you inject a Spy object that will help you validate the correct behaviour:

    final class UIViewControllerSpy: ViewControllerPresenting {
        var viewControllerToPresent: UIViewController!
    
        func present(_ viewControllerToPresent: UIViewController,
                     animated flag: Bool,
                     completion: (() -> Void)? = nil) {
            self.viewControllerToPresent = viewControllerToPresent
        }
    }
    
    class DownloadBaseViewControllerTests: XCTestCase {
    
       var downloadBaseViewController: DownloadBaseViewController! = DownloadBaseViewController()
    
       func testDecisionEmptyTreeFeedbackButtonTapped() throws {
           // Given
           let spyController = UIViewControllerSpy()
           downloadBaseViewController.presentingController = spyController
           // When
           downloadBaseViewController.decisionEmptyTreeFeedbackButtonTapped()
           // Then
           let presentedController = spyController.viewControllerToPresent as? PremiumFeedbackViewController
           XCTAssertNotNil(presentedController, "Download base view controller contains feedback view controller and succesfully able to navigate")
       }
    }