Swift 手动触发UITableViewRowAction处理程序
在swift中,我需要测试表视图单元格的删除。每个单元格都有两个与之关联的行操作,其中一个是删除该单元格 如何在此行操作上手动调用处理程序? 这是执行删除操作的函数Swift 手动触发UITableViewRowAction处理程序,swift,uitableview,callback,uitableviewrowaction,Swift,Uitableview,Callback,Uitableviewrowaction,在swift中,我需要测试表视图单元格的删除。每个单元格都有两个与之关联的行操作,其中一个是删除该单元格 如何在此行操作上手动调用处理程序? 这是执行删除操作的函数 private func deleteCellAtRow(row: Int) { let deleteCell = NSIndexPath(forRow: row, inSection: 0) // get the actions corresponding to the cell at that index
private func deleteCellAtRow(row: Int) {
let deleteCell = NSIndexPath(forRow: row, inSection: 0)
// get the actions corresponding to the cell at that index
let actions : [UITableViewRowAction] = self.tableView(self.queue, editActionsForRowAtIndexPath: deleteCell)!
// Get a reference to the delete button for that cell
let predicate : NSPredicate = NSPredicate(format: "title MATCHES[c] '.*delete'")
if let action = (actions as NSArray).filteredArrayUsingPredicate(predicate).first as? UITableViewRowAction {
// What to do now??
// Call the callback
}
}
不幸的是,我也有同样的需要,我没有找到一个干净的方法来做 无论如何,由于手动触发器的目的只是对操作进行单元测试(在我的例子中也是如此),因此我们可以检查
UITableViewRowAction
类的私有头并手动触发所需的API显然,这不能在生产中完成,但只能在测试套件中完成,否则应用程序将被拒绝强>
注意:我只在iOS 9.3上测试过这个,因为它使用的是私有API,所以它可能会停止使用较新版本的iOS。
解决方案
在测试包的桥接头中添加这些行(或者在单独的文件中,只要在桥接头中导入)
通过这种方式,我们公开了UITableViewRowAction
的私有属性\u handler
现在,在我们的swift文件中,我们可以这样做:
private func deleteCellAtRow(row: Int) {
let deleteCell = NSIndexPath(forRow: row, inSection: 0)
// get the actions corresponding to the cell at that index
let actions : [UITableViewRowAction] = self.tableView(self.queue, editActionsForRowAtIndexPath: deleteCell)!
// Get a reference to the delete button for that cell
let predicate : NSPredicate = NSPredicate(format: "title MATCHES[c] '.*delete'")
if let action = (actions as NSArray).filteredArrayUsingPredicate(predicate).first as? UITableViewRowAction {
// OUR SOLUTION
action._handler(action, indexPath)
// And now you can test!
}
}
不幸的是,我也有同样的需要,我没有找到一个干净的方法来做 无论如何,由于手动触发器的目的只是对操作进行单元测试(在我的例子中也是如此),因此我们可以检查
UITableViewRowAction
类的私有头并手动触发所需的API显然,这不能在生产中完成,但只能在测试套件中完成,否则应用程序将被拒绝强>
注意:我只在iOS 9.3上测试过这个,因为它使用的是私有API,所以它可能会停止使用较新版本的iOS。
解决方案
在测试包的桥接头中添加这些行(或者在单独的文件中,只要在桥接头中导入)
通过这种方式,我们公开了UITableViewRowAction
的私有属性\u handler
现在,在我们的swift文件中,我们可以这样做:
private func deleteCellAtRow(row: Int) {
let deleteCell = NSIndexPath(forRow: row, inSection: 0)
// get the actions corresponding to the cell at that index
let actions : [UITableViewRowAction] = self.tableView(self.queue, editActionsForRowAtIndexPath: deleteCell)!
// Get a reference to the delete button for that cell
let predicate : NSPredicate = NSPredicate(format: "title MATCHES[c] '.*delete'")
if let action = (actions as NSArray).filteredArrayUsingPredicate(predicate).first as? UITableViewRowAction {
// OUR SOLUTION
action._handler(action, indexPath)
// And now you can test!
}
}
一个更复杂,但也许更能证明未来的解决方案是使用接缝。有关接缝的更多信息,请阅读。我们可以使用同样的技术模拟初始值设定项。首先,将以下内容添加到项目中:
import UIKit
let defaultUITableViewRowActionInit: (UITableViewRowAction.Style, String?, @escaping (UITableViewRowAction, IndexPath) -> Void) -> UIKit.UITableViewRowAction = { style, title, handler in
return UIKit.UITableViewRowAction(style: style, title: title, handler: handler)
}
var uiTableViewRowActionInit = defaultUITableViewRowActionInit
func UITableViewRowAction(style: UITableViewRowAction.Style, title: String?, handler: @escaping (UITableViewRowAction, IndexPath) -> Void) -> UIKit.UITableViewRowAction {
return uiTableViewRowActionInit(style, title, handler)
}
从现在开始,对UITableVeiwRowAction的调用将通过我们的函数,而不是普通的初始值设定项。在正常的产品使用过程中,行为将是相同的。对于测试,我们现在可以先添加模拟:
class UITableViewRowActionMock: UITableViewRowAction {
var passedStyle: UITableViewRowAction.Style
var passedTitle: String?
var passedHandler: (UITableViewRowAction, IndexPath) -> Void
init(style: UITableViewRowAction.Style, title: String?, handler: @escaping (UITableViewRowAction, IndexPath) -> Void) {
passedStyle = style
passedTitle = title
passedHandler = handler
}
}
此类仅捕获传递给它的参数,包括块。从这里开始,我们需要我们的测试设置和拆卸来设置和拆卸接缝:
override func setUp() {
super.setUp()
// CODE ...
uiTableViewRowActionInit = { style, title, handler in
return UITableViewRowActionMock(style: style, title: title, handler: handler)
}
}
override func tearDown() {
// CODE ...
uiTableViewRowActionInit = defaultUITableViewRowActionInit
super.tearDown()
}
从那里,我们可以运行我们的测试:
func testEditActionSomehow() {
let indexPath = IndexPath(row: 0, section: 0)
// here I just grab, first, feel free to do something more complicated
guard let action = sut.tableView(sut.tableView, editActionsForRowAt: indexPath)?.first as? UITableViewRowActionMock else {
XCTFail("Unexpected type")
return
}
action.passedHandler(action, indexPath)
//
在此处添加断言代码
}
但是,如果您有很多案例要测试,您可能希望将大部分代码从您的操作中提取到更易于测试的地方。一个更复杂但可能更经得起未来考验的解决方案是使用seam。有关接缝的更多信息,请阅读。我们可以使用同样的技术模拟初始值设定项。首先,将以下内容添加到项目中:
import UIKit
let defaultUITableViewRowActionInit: (UITableViewRowAction.Style, String?, @escaping (UITableViewRowAction, IndexPath) -> Void) -> UIKit.UITableViewRowAction = { style, title, handler in
return UIKit.UITableViewRowAction(style: style, title: title, handler: handler)
}
var uiTableViewRowActionInit = defaultUITableViewRowActionInit
func UITableViewRowAction(style: UITableViewRowAction.Style, title: String?, handler: @escaping (UITableViewRowAction, IndexPath) -> Void) -> UIKit.UITableViewRowAction {
return uiTableViewRowActionInit(style, title, handler)
}
从现在开始,对UITableVeiwRowAction的调用将通过我们的函数,而不是普通的初始值设定项。在正常的产品使用过程中,行为将是相同的。对于测试,我们现在可以先添加模拟:
class UITableViewRowActionMock: UITableViewRowAction {
var passedStyle: UITableViewRowAction.Style
var passedTitle: String?
var passedHandler: (UITableViewRowAction, IndexPath) -> Void
init(style: UITableViewRowAction.Style, title: String?, handler: @escaping (UITableViewRowAction, IndexPath) -> Void) {
passedStyle = style
passedTitle = title
passedHandler = handler
}
}
此类仅捕获传递给它的参数,包括块。从这里开始,我们需要我们的测试设置和拆卸来设置和拆卸接缝:
override func setUp() {
super.setUp()
// CODE ...
uiTableViewRowActionInit = { style, title, handler in
return UITableViewRowActionMock(style: style, title: title, handler: handler)
}
}
override func tearDown() {
// CODE ...
uiTableViewRowActionInit = defaultUITableViewRowActionInit
super.tearDown()
}
从那里,我们可以运行我们的测试:
func testEditActionSomehow() {
let indexPath = IndexPath(row: 0, section: 0)
// here I just grab, first, feel free to do something more complicated
guard let action = sut.tableView(sut.tableView, editActionsForRowAt: indexPath)?.first as? UITableViewRowActionMock else {
XCTFail("Unexpected type")
return
}
action.passedHandler(action, indexPath)
//
在此处添加断言代码
}
但是,如果您有很多案例需要测试,您可能希望将大部分代码从操作中提取到更易于测试的地方。这是一个很好的解决方法。假设,这应该是acceptedit很好的解决方法。假设,它应该被接受