单元测试 UICollectionView.indexPath(针对:UICollectionViewCell)

Unit Testing UICollectionView.indexPath(for: UICollectionViewCell)

我正在尝试在 ViewController

中对这段代码进行单元测试
    func categoryTextEditedAt(_ cell: UICollectionViewCell, _ text: String) {
        guard let indexPath = self.collectionView.indexPath(for: cell), text != "" else {return}

        //Rest of the codes to be tested
    }

而在我的单元测试中测试上面的功能如下:

    func testCategoryTextEditedAt() {
        sut.viewDidLoad()
        sut.collectionView.reloadData()
        let cell = sut.collectionView.dataSource?.collectionView(sut.collectionView, cellForItemAt: IndexPath(item: 0, section: 0))
        sut.categoryTextEditedAt(cell!, "testString")
    }

但我一直在为 categoryTextEditedAt(:) 函数中的 indexPath 获取 'nil'。在调试时,我发现 testCategoryTextEditedAt() 单元格内部有一个值,但 self.collectionView.indexPath(for:cell) 一直返回 'nil' for 'indexPath.'

我该如何进行这个过程?

我猜你的问题是因为你试图在错误的地方测试代码。

想象一下,如果你必须测试一个单元函数,你需要实例化所有 UICollection 结构,这是一种难闻的气味。

例如,您可以这样做。

enum UseCaseError {
    textEmpty
}

class UseCase {
    private let index: Int
    private let text: String
    init(index: Int, text: String) {
        self.index = index
        self.text = text
    }

    public func execute() throws {
        guard text.isEmpty == false else {
            throw UseCaseError.textEmpty
        }

        // your logic here to be tested
    }
}

查看此 UseCase,您可以测试何时 text 为空以及您所有的业务逻辑

现在你只需要将它放入categoryTextEditedAt方法

func categoryTextEditedAt(_ cell: UICollectionViewCell, _ text: String) {
    guard let indexPath = self.collectionView.indexPath(for: cell) { return }
    try? UseCase(index: indexPath.item, text: text).execute()
}

如果您将代码分开,您可以在之前对其进行测试,并且您无需浪费时间尝试使 UIKit 函数正常工作,只需您的逻辑即可。

希望对这个例子有所帮助。

对于那些对如何对 collectionViewDelegateMethod 进行单元测试感到好奇的人:

    func categoryTextEditedAt(_ cell: UICollectionViewCell, _ text: String) {
        guard let indexPath = self.collectionView.indexPath(for: cell), text != "" else {return}

        //Rest of the codes to be tested
    }

你可以做类似

func testCategoryTextEditedAt() {
    class MockCV: UICollectionView {
        override func indexPath(for cell: UICollectionViewCell) -> IndexPath? {
            let anyIndexPathWhichEverYoulike = IndexPath(item:0, section:0)
            return anyIndexPathWhichEverYoulike
        }
    }
    sut.collectionView = MockCV()
    let cell = sut.collectionView.dataSource?.collectionView(sut.collectionView, cellForItemAt: IndexPath(item: 0, section: 0))
    sut.categoryTextEditedAt(cell!, "testString")
}