【问题标题】:Unit Testing UICollectionView.indexPath(for: UICollectionViewCell)单元测试 UICollectionView.indexPath(for: UICollectionViewCell)
【发布时间】:2020-01-13 07:36:37
【问题描述】:

我正在尝试在 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) 不断为 'indexPath' 返回 'nil'。

我该如何进行这个过程?

【问题讨论】:

  • 您是否在测试中提供了集合视图的数据源?
  • 是的,我在测试的初始化部分做了。
  • sut.collectionView.dataSource = ...的代码在哪里添加?
  • 它由 userDefault -> Model -> sut 提供。正如我上面提到的,细胞不是零。如果我打印单元格,则打印如下 = "Optional(>)"
  • 但是如果您知道在测试功能中提供数据源的其他方法,我很高兴看到它。

标签: ios swift unit-testing uikit collectionview


【解决方案1】:

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

想象一下,如果你必须测试一个单元函数,你需要实例化所有 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 函数正常工作,只需您的逻辑即可。

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

【讨论】:

  • 感谢您的回复,这可以替代我的方法,但我希望尽量减少新类的引入,只是为了单元测试。
  • 通常,collectionView CellFotItem 或 didSelect 或任何其他委托和数据源方法可以使用依赖注入或模拟进行测试
  • 希望您能找到更适合您情况的解决方案
【解决方案2】:

对于那些好奇如何对 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")
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    • 2015-01-25
    • 2019-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-02
    相关资源
    最近更新 更多