UITableViewのUnitTestを書く

More than 1 year has passed since last update.

iOSアプリで、UITableViewが期待通りの挙動をするかのテストを書くメモです。

最近はStoryboardを使わずにレイアウトもすべてコードで書いているので、そのように書きます。


実装

持っているアイテムの数だけCellを表示する簡単な画面を想定します。

スクリーンショット 2018-03-27 12.54.24.png

// ViewController.swift

import UIKit

class ViewController: UIViewController {

let tableView = UITableView()
var items = ["Hello", "World", "Swift 4", "Xcode 9.2", "iPhone X", "WWDC 2018"]

override func viewDidLoad() {
super.viewDidLoad()

view.addSubview(tableView)

// TableViewを画面いっぱいに貼る
tableView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
tableView.rightAnchor.constraint(equalTo: view.rightAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])

tableView.dataSource = self
}
}

extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 2 // ヘッダー + コンテンツ
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
} else {
return items.count
}
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell()
if indexPath.section == 0 {
cell.textLabel?.text = "TableViewのテストのサンプルです"
cell.textLabel?.font = UIFont.systemFont(ofSize: 14.0)
cell.textLabel?.textColor = .gray
cell.textLabel?.textAlignment = .center
} else {
cell.textLabel?.text = items[indexPath.row]
}
return cell
}
}

この ViewController について、TableView のテストを書いていきます。


テストコード


準備

UnitTest Bundleに TableViewTestSampleTests.swift というファイルを追加して、ここにテストを追加していきます。

まず、@testable import TableViewTestSample を宣言します。

これにより UnitTest から実装のコードを参照できるようになり、上記で準備して ViewController にアクセスできるようになります。

// TableViewTestSampleTests.swift

import XCTest
@testable import TableViewTestSample

class TableViewTestSampleTests: XCTestCase { ... }


TableViewが表示されていることを確認するテスト

インスタンスが生成されていること、addSubviewされていることを確認します。

class TableViewTestSampleTests: XCTestCase {

func test_tableViewが表示されること() {
let vc = ViewController()
XCTAssertNotNil(vc.tableView)
XCTAssertTrue(vc.view.subviews.contains(vc.tableView))
}
}


Sectionの数を確認するテスト

Sectionは「ヘッダー」「コンテンツ」の2つあります。

確認するテストは以下のようになります。

import XCTest

@testable import TableViewTestSample

class TableViewTestSampleTests: XCTestCase {
// ...

func test_sectionが2つあること() {
let vc = ViewController()

let sectionCount = vc.numberOfSections(in: vc.tableView)
XCTAssertEqual(sectionCount, 2)
}
}

テスト名は test から始まっていれば自由に名付けられます。

最近は意味が分かりやすいよう、テスト名を日本語にしています。


Rowの数を確認するテスト

1つ目のSectionにはヘッダーの1つだけ、

2つ目のSectionにはアイテムの数だけCellが表示されることを確認します。

class TableViewTestSampleTests: XCTestCase {

// ...

func test_1つ目のsectionにはセルが1つだけであること() {
let vc = ViewController()

let rowCount = vc.tableView(vc.tableView, numberOfRowsInSection: 0)
XCTAssertEqual(rowCount, 1)
}

func test_2つ目のsectionには与えられたアイテムの数だけセルが表示されること() {
let vc = ViewController()

// ダミーのデータを設定する
let testItems = ["test-item-1", "test-item-2"]
vc.items = testItems

let rowCount = vc.tableView(vc.tableView, numberOfRowsInSection: 1)
XCTAssertEqual(rowCount, testItems.count)
}
}


Cellに表示されるラベルの内容を確認するテスト

期待通り Cell にテキストが表示されていることを確認します。

class TableViewTestSampleTests: XCTestCase {

// ...

func test_Cellのテキストに期待されたラベルが表示されていること() {
let vc = ViewController()

let testItems = ["test-item-1"]
vc.items = testItems

let cell = vc.tableView(vc.tableView, cellForRowAt: IndexPath(row: 0, section: 1))
XCTAssertEqual(cell.textLabel?.text, "test-item-1")
}
}

セルの表示に関するテストは ViewController ではなくセルのテストとして行うべきかもしれませんが、ここでは簡単のためこのクラスに書いてます。

また、Cell を取得する部分で UITableView のメソッドを使って、

vc.tableView.cellForRow(at: IndexPath(row: 0, section: 1))

このように記述することもできますが、これは表示中のセルしか取得できないので注意が必要です。


まとめ

UITableView をテストするユニットテストの書き方をいくつか紹介しました。

タップイベントなども同じように書くことができるので参考にしてみてください。

サンプルコードはこちらに貼っておきます。


関連