Search code examples
swiftunit-testinguitableview

Table View Outlet unit testing failed


I am using storyboard and I have the outlet created into View controller.In view did load I have setup the delegate and datasource to self . I am trying to write unit test for Table view Outlet but Actually, It return nil although, it exists..

Here is the view model code ..

class CakeListViewModel: CakeListViewModelType {
    

    weak private var delegate: CakeListViewType!
    let service:Service!
    
    private var cakes:[Cake]?
    
    var itemCount: Int {
        return cakes?.count ?? 0
    }
    
    init(delegate: CakeListViewType,
         service:Service = ServiceImpl()) {
        self.delegate = delegate
        self.service = service
    }
    
    /*
     this method connect calls rest API to get data
     */
    func fetchCakes() {
        let client = ServiceClient(baseUrl:EndPoints.baseUrl.rawValue, path:Path.cakeList.rawValue, params:"", method:"get")
        
        service.fetchData(client:client, type:Cake.self) { [weak self] (result)  in
            switch result {
            case .success(let result):
                self?.cakes = result
                DispatchQueue.main.async {
                    self?.delegate?.updateUI()
                }
            case .failure(_):
                self?.cakes = nil
                DispatchQueue.main.async {
                    self?.delegate?.showError()
                }
            }
        }
    }
}

Here is my test code ..

class CakeViewModelTest: XCTestCase {
    
    var mockService:MockService!
    var viewModel:CakeListViewModel!


    override func setUp() {
        mockService = MockService()
        let vc = CakeListViewController()
        viewModel = CakeListViewModel(delegate:vc, service:mockService)
    }

    func testTableViewOutlet() {
        let vc =  CakeListViewController()
        XCTAssertNotNil(vc.tableView)
    }
}

Here is my view controller code ..

class CakeListViewController: UIViewController {
    
    @IBOutlet var tableView: UITableView!
    
    var viewModel:CakeListViewModelType!
    weak var coordinator: Coordinator?

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        tableView.delegate = self
        title = "🎂CakeItApp🍰"
        
        viewModel.fetchCakes()
    }
}

Here is the screenshot of the error ..

error in view model in view did load

error


Solution

  • The view controller initializer you are using does make any use of the storyboard. So nothing you've setup in the storyboard (outlets, constraints, etc.) will exist in the view controller. You need to replace the line:

    let vc = CakeListViewController()
    

    with code more like this:

    if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "YourViewControllerID") as? CakeListViewController {
    }
    

    Replace "Main" with the name of your storyboard (if it isn't actually "Main").

    Replace "YourViewControllerID" with the actual ID you gave the view controller in the storyboard.


    With that fixed, you will run into more issues. Your CakeListViewController has an implicitly unwrapped optional named viewModel that is accessed in viewDidLoad. So you must ensure that you set viewModel immediately after creating the view controller.

    if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "YourViewControllerID") as? CakeListViewController {
        vc.viewModel = someViewModelInstance
        // Do your tests here
    }