【发布时间】:2021-07-14 04:52:09
【问题描述】:
我正在为我的 UITableViewController 的数据源编写单元测试,它有一个用于过滤结果的 UISearchController。我需要测试 NumberOfRowsInSection 中的逻辑,以便当搜索控制器处于活动状态时,数据源会从过滤后的数组而不是普通数组中返回计数。
该函数通过检查搜索控制器的“isActive”是否为真/假来控制这一点。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return searchController.isActive ? filteredResults.count : results.count
}
所以我的单元测试是这样写的
func testNumberOfRowsInSection() {
XCTAssertFalse(searchController.isActive)
XCTAssertEqual(4, dataSource.tableView(tableView, numberOfRowsInSection: 0))
searchController.isActive = true
XCTAssertTrue(searchController.isActive) // Fails right after setting it true
XCTAssertEqual(0, dataSource.tableView(tableView, numberOfRowsInSection: 0)) // Fails
searchController.isActive = false
XCTAssertFalse(searchController.isActive)
XCTAssertEqual(4, dataSource.tableView(tableView, numberOfRowsInSection: 0))
}
因此,在单元测试中将“isActive”属性设置为 true 后,它不会立即保持为 true。这很奇怪,因为在应用程序的常规运行期间,我可以在视图控制器中将其设置为 true 并保持活动状态。
override func viewDidLoad() {
super.viewDidLoad()
// ...
searchController.isActive = true // Makes search bar immediately visible
// ...
}
文档显示它是一个可设置的属性,那么为什么在单元测试中不将其设置为 true 呢?我也尝试将它附加到导航栏,但这并没有改变任何东西。如果我不能在单元测试中像这样测试它,我将不得不模拟该功能,这会很烦人,因为测试它应该很简单。
更新示例:
class MovieSearchDataSourceTests: XCTestCase {
private var window: UIWindow!
private var controller: UITableViewController!
private var searchController: UISearchController!
private var sut: MovieSearchDataSource!
override func setUp() {
window = UIWindow()
controller = UITableViewController()
searchController = UISearchController()
sut = MovieSearchDataSource(tableView: controller.tableView,
searchController: searchController,
movies: Array(repeating: Movie.test, count: 4))
window.rootViewController = UINavigationController(rootViewController: controller)
controller.navigationItem.searchController = searchController
}
override func tearDown() {
window = nil
controller = nil
searchController = nil
sut = nil
RunLoop.current.run(until: Date())
}
func testNumberOfRowsInSection() {
window.addSubview(controller.tableView)
controller.loadViewIfNeeded()
XCTAssertFalse(searchController.isActive)
XCTAssertEqual(4, sut.tableView(controller.tableView, numberOfRowsInSection: 0))
searchController.isActive = true
XCTAssertTrue(searchController.isActive)
XCTAssertEqual(0, sut.tableView(controller.tableView, numberOfRowsInSection: 0))
searchController.isActive = false
XCTAssertFalse(searchController.isActive)
XCTAssertEqual(4, sut.tableView(controller.tableView, numberOfRowsInSection: 0))
}
}
【问题讨论】:
-
涉及 UISearchController 甚至表视图的测试不是单元测试。您应该模拟控制器并仅测试被测系统。您的代码使用术语
sut,但未能理解其含义。sut不应该涉及苹果的代码!我们知道它的作用。它应该是你的代码。 -
在尝试另一种方式之后,我同意模拟控制器最终是更简单的解决方案。我不明白的是为什么你说有一个表格视图使它不是一个单元测试。我如何在没有表格视图的情况下测试
tableView:numberOfRowsInSection中的我的 代码逻辑?
标签: swift unit-testing uikit xctest uisearchcontroller