【问题标题】:What's the best way to assert on a UIImage in a unit test?在单元测试中断言 UIImage 的最佳方法是什么?
【发布时间】:2023-03-10 05:04:01
【问题描述】:

假设我正在为视图控制器上的 tableView:cellForRowAtIndexPath: 委托方法编写单元测试。根据我传入的索引路径,此方法可能会返回几种不同的单元格配置。

我可以轻松地断言 cell.textLabel.text 属性。但是我如何断言cell.imageView.image 属性包含正确的图像?图像或 imageView 都没有(公共 API)属性,我可以使用它来找出图像名称或文件名。

我想出的最好的方法是创建smallest possible valid .png(使用[UIImage imageWithData:],所以我在单元测试中不会触及磁盘)并断言我从cell.imageView.image得到的字节数组是我的预计。我创建了一个OCHamcrest matcher 来使它更好一点,但这是一种不令人满意且不灵活的方法。

有人有更好的主意吗?

【问题讨论】:

  • 图片是从项目还是网页加载?
  • 来自项目。如果我想对下载的图像进行断言,我会在进行下载的类前面放置一个外观,并在测试中对其进行模拟。

标签: ios objective-c unit-testing ocmockito


【解决方案1】:

如果您使用的是[UIImage imagedNamed:],则图像会被缓存。摘自UIImage class reference for imagedNamed:

此方法在系统缓存中查找具有指定名称的图像对象,如果该对象存在,则返回该对象。如果缓存中没有匹配的图像对象,则此方法从指定文件加载图像数据,缓存它,然后返回结果对象。

这意味着您可以在cell.imageView.image == [UIImage imagedName:@"my_image"] 上进行断言,因为这是一个指针比较,并且由于图像被缓存,多次调用imageNamed: 以相同的名称将返回相同的指针。正如 UIImage 类参考解释的那样,即使内存变得紧张,您仍然应该没问题:

在内存不足的情况下,可能会从 UIImage 对象中清除图像数据以释放系统内存。这种清除行为只影响 UIImage 对象内部存储的图像数据,而不影响对象本身。

【讨论】:

  • 哦,哇,我没有意识到这一点。很棒的答案。阻止我立即接受这一点的一件事是使用 [UIImage imageNamed:] 意味着磁盘访问,如果可以的话,我想在单元测试中避免这种情况。
  • 没有磁盘,但是如果请求的图像是缓存未命中,文件系统访问会产生轻微的开销。如果是缓存命中,那就是内存读取。
  • 这似乎不再适用于 Xcode 6.4。我不得不改用XCTAssertEqualObjects(image, [UIImage imageNamed:@"myImage"])
【解决方案2】:

您可以直接使用UIImage 上的isEqual 方法比较UIImage 的内容,这将比较两个图像的相似之处。

所以在你的测试中,你可以这样做:

let expectedImage = UIImage(named: "my_picture")
let returnedImage = SomeImageReturnedFromFunction()
XCTAssertEqualObjects(expectedImage, returnedImage) // will return true if SomeImageReturnedFromFunction returns my_picture

参考:https://developer.apple.com/documentation/uikit/uiimage#overview

【讨论】:

    【解决方案3】:

    将图像转换为数据,然后比较数据。由于图像只是指向内存位置的指针。

    guard let data1 = image1?.pngData(), let data2 = image2.pngData() else {
        XCTFail("Data should not be nil")
        return
    }
    XCTAssertEqual(data1, data2)
    

    swift5

    【讨论】:

    • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
    • 这是最好的答案。
    【解决方案4】:

    您确实可以与“isEqual”方法进行比较,但更像这样:

    let expectedImage = UIImage(named: "an_image")
    let returnedImage = myFunctionRet() // optional ?
    
    XCTAssert(returnedImage?.isEqual(expectedImage) == true)
    

    【讨论】:

      猜你喜欢
      • 2015-04-07
      • 1970-01-01
      • 2010-09-08
      • 1970-01-01
      • 1970-01-01
      • 2012-05-22
      • 1970-01-01
      • 2019-02-12
      • 2016-01-16
      相关资源
      最近更新 更多