我正在学习TTD,并且在单元测试中遇到导航控制器问题。
当我尝试使用我的模拟控制器通过导航堆栈(pushViewController(ViewController,animation :))推送详细视图控制器时,在测试推送功能中无法执行(仅当NavigationController初始化时才执行)。
在模拟iPhone上,应用程序可以正常运行。
在代码中,mockNavigationController具有pushVC值,当pushViewController执行时该值会更改。
当用户点击单元格时,dataProvider(tableCell的委托和dataSource)将通知发布到ViewController(sut),该通知实现了showDetails方法。
我会尝试从navigationController中获取topViewController:
sut.navigationController?.topViewController-返回sut ViewController。
尝试不要在测试中初始化navigationController。 sut.navigationController?.topViewController-返回nil。
XCTestCase的开始
var sut: EatersListViewController!
override func setUp() {
super.setUp()
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier: String(describing: EatersListViewController.self))
sut = vc as? EatersListViewController
sut.loadViewIfNeeded()
}
此测试功能
func testSelectedRowPushedDetailVC() {
let mockNavigationController = MockNavigationController(rootViewController: sut)
UIApplication.shared.keyWindow?.rootViewController = mockNavigationController
let eater1 = Eater(name: "Foo")
sut.dataProvider.manager!.addEater(eater: eater1)
sut.loadViewIfNeeded()
sut.tableView.delegate?.tableView?(sut.tableView, didSelectRowAt: IndexPath(row: 0, section: 0))
guard let detailEaterVC = mockNavigationController.pushedVC as? DetailEaterViewController else {
XCTFail()
return
}
detailEaterVC.loadViewIfNeeded()
XCTAssertNotNil(detailEaterVC.eaterNameLabel)
XCTAssertEqual(detailEaterVC.eaterData, eater1)
}
来自ViewController的此功能
@objc func showDetails(withNotification notification: Notification) {
guard
let userInfo = notification.userInfo,
let eater = userInfo["eater"] as? Eater,
let detailEaterVC = storyboard?.instantiateViewController(withIdentifier: String(describing: DetailEaterViewController.self)) as? DetailEaterViewController else { return }
detailEaterVC.eaterData = eater
navigationController?.pushViewController(detailEaterVC, animated: true)
}
和MockNavigationController
extension EatersListViewControllerTests {
class MockNavigationController: UINavigationController {
var pushedVC: UIViewController?
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
pushedVC = viewController
super.pushViewController(viewController, animated: animated)
}
}
}
我希望XCTAssert可以正常工作,但是每次测试都在XCTFail()行上失败。我认为某个地方有错误,在这里不知道。
XCTAssertNotNil(detailEaterVC.eaterNameLabel)
XCTAssertEqual(detailEaterVC.eaterData, eater1)
在错误的地方需要代码帮助。谢谢阅读。
最佳答案
嗨,@Alexander,欢迎来到StackOverflow。 👋
您说dataProvider
是被测视图控制器中.dataSource
的.delegate
和UITableView
,并且它是启动导航的负责人。
您确定测试中dataProvider
实际上设置为.dataSource
和.delegate
吗?如果不是这种情况,那么将永远不会调用启动导航的代码。
您可以使用断点来验证两件事:
如果您的showDetails
方法被调用
如果pushViewController(_:, animated:)
中的MockNavigationController
方法被调用
我猜其中一个没有被调用,这可能会指出问题的原因。
如果允许的话,请多说几句:
我建议使用NavigationDelegate
pattern测试此行为。通过消除使用UIApplication
的麻烦,这将使您更轻松。
最好在测试中使用_ = sut.view
或sut.beginAppearanceTransition(true, animated: false)
触发视图控制器视图的设置