I have a ViewController that contains a tableView. Since I need to keep the code well covered with tests, I need to write a test for [tableView:cellForRowAtIndexPath]
import UIKit
class MainViewController: UIViewController, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
var source = [
Country(name: "USA", capital: "Washington, D.C."),
Country(name: "Argentina", capital: "Buenos Aires"),
Country(name: "Mexico", capital: "Mexico, D.F.")
]
let cellIdentifier = NSStringFromClass(MainViewController.self)
init() {
super.init(nibName: "MainViewController", bundle: nil)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName: "CustomCell", bundle: nil)
tableView?.registerNib(nib, forCellReuseIdentifier: cellIdentifier)
tableView.dataSource = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return source.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? CustomCell
if let cell = cell {
cell.countryLabel.text = source[indexPath.row].name
cell.capitalLabel.text = source[indexPath.row].capital
return cell
}
return CustomCell()
}
}
struct Country {
var name: String
var capital: String
}
The tests look like the following:
import UIKit
import XCTest
class MainViewControllerTests: XCTestCase {
var controller: MainViewController!
override func setUp() {
super.setUp()
controller = MainViewController()
controller.view.description
}
override func tearDown() {
super.tearDown()
}
func testTableViewOutlet() {
XCTAssertNotNil(controller.tableView)
}
func testTableViewCellForRowAtIndexPath() {
let indexPath = NSIndexPath(forRow: 0, inSection: 0)
let cell = controller.tableView(controller.tableView, cellForRowAtIndexPath: indexPath) as! CustomCell
XCTAssertEqual(cell.countryLabel.text!, "USA")
XCTAssertEqual(cell.capitalLabel.text!, "Washington, D.C.")
}
}
I get the following error when running the tests:
Test Case '-[CustomTableViewCellTests.MainViewControllerTests testTableViewCellForRowAtIndexPath]' started.
fatal error: unexpectedly found nil while unwrapping an Optional value
This function has alluded tests for months in my production application since [dequeueReusableCellWithIdentifier] returns nil only when run from the tests. I have actually tried many different approaches I have read in StackOverflow, like:
The bottom line is that I get close to a solution, I create an CustomCell object, but the outlets for the cell remain nil. I haven't found the piece of code that would realize the outlets into initialized elements so I can make my tests pass.
I am including a basic iOS project with its own git which contains the code that I have included here. It is a UIViewController that contains UITableView which displays data using a custom UITableViewCell. I'm hoping a find a solution that realizes the custom cell with its outlets to make the test pass.
Git repo source: https://bitbucket.org/jallauca/customcell/src
To clone the git repo:
git clone https://bitbucket.org/jallauca/customcell.git
For me, (Swift 3) I had to call the cellForRow datasource cellForRowAt function instead of accessing straight from the tableView.cellForRow function
//this
let cell = controller.tableView(controller.tableView, cellForRowAt: IndexPath(row: 0, section: 0))
//instead of this
let cell = controller.tableView.cellForRow(at: IndexPath(row: 0, section: 0))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With