【问题标题】:Need help understanding difference in raw image binary data for PHPUnit test需要帮助了解 PHPUnit 测试的原始图像二进制数据的差异
【发布时间】:2011-08-22 15:25:05
【问题描述】:

所以我编写了一个单元测试来比较 PHP 中的裁剪图像(使用 imagemagick)。该测试有效,但是在一次比较大量图像时遇到了问题。根据创建图像的时间,每个图像都会收到一个直接嵌入到原始数据中的时间戳。在比较文件之前,我一直在使用正则表达式提取该时间戳,但似乎每隔一段时间,其中一个图像文件将包含额外的原始数据,即使它们完全相同。

举个例子,这是我的一项测试的结果(注意,我将图像的二进制数据作为字符串进行比较):

ImageTest::testAutoCrop

断言两个字符串相等失败。

--- 预期

+++实际

@@@@

?n??m?

-?F soO=f???????^???????w??>

                          ?(???/o????M)???o%tEXt??%tEXt

+?F sO=f???????^???????w??>

                          ?(???/o????M)???o%tEXt

如您所见....这两个文件之间的唯一区别是预期图像中包含以下附加字符串:“?%tEXt”。

谁能帮我理解这个随机数据代表什么?这将帮助我弄清楚如何修改我的单元测试,这样这样的问题就不会再发生了。

谢谢,

马尔科姆

PS:如果我需要提供更多信息,请告诉我。

【问题讨论】:

  • 什么 imagemagick API?什么图像格式? (Imagemagick 有一个“-strip”选项,但它似乎不适用于 PNG。)

标签: php string imagemagick compare phpunit


【解决方案1】:

所以我最终想出了解决这个问题的办法。需要澄清的几件事:

  1. 我进行单元测试的原因是因为我们的图像服务 Web 应用程序 (PHP) 使用 Imagemagick 来处理所有图像处理、操作、HTML 到图像的转换以及 PDF 到图像 (jpg,png,gif,在我们的主网站上发生的所有非 cmyk, pdf ) 转换。需要确保在我们向该图像服务应用程序添加新功能时,进行了足够的测试以确保一切仍然正常运行。

  2. 我们在每个图像中看到的字符串数据(又名:?%tEXt)是图像的 exif 数据。 (http://en.wikipedia.org/wiki/Exchangeable_image_file_format)为了比较图片(建议取自 David Andersson 的回复(https://stackoverflow.com/users/904933/david-andersson),我们需要从图片中完全删除所有评论数据以及创建日期时间戳/修改信息。这样你'只处理一张图片,没有其他类型的元数据。我们使用以下函数来处理:


protected static function _removeTimeStamp( $string, $pdf = false ) {

  /* Note: Assume $string parameter is the image you're planning on cleaning in string format. */

  /* If you're working with a pdf, you need to remove the CreationDate using regex from the string representation. */
  if ( $pdf )
    return preg_replace( '/(CreationDate[^)]+)/', '', $string );

  /* Create a path for the temporary image we're going to need to create that will hold the exif free image */
  $strip_tmp = 'test/strip_tmp';

  /* write contents of string to temp string file */
  file_put_contents( $strip_tmp, $string );

  /* this will remove all exif data along with the date:create and date:modify properties from the image */
  exec( 'convert ' . $strip_tmp . ' -strip +set date:create +set date:modify ' . $strip_tmp . ' 2> /dev/null' ); 

  /* get the string representation of the new "cleaned" image */
  $result = file_get_contents( $strip_tmp ); 

  /* delete the temp file */
  unlink( $strip_tmp ); 

  /* return the cleaned string */
  return $result;

} // _removeTimeStamp

这是在将它们相互比较之前在每个图像上运行的(以字符串格式)。希望这对将来可能会做类似事情的人有所帮助。

我计划写一篇更详细的博客文章来展示我是如何处理其他一些测试的。当我这样做时,我将使用 cmets 或此答案中的链接更新此问题。希望这对某人有所帮助。

【讨论】:

  • 天啊! PHP中二进制数据的字符串比较...必须知道你的东西,嗯? (1) 去除元数据差异 (2) 创建数据的 md5sum 然后 (3) 比较两个 md5sum 不是更有效吗?!?
  • Kurt,这肯定也可以工作,而且可能会更有效率。我没有立即这样做的唯一原因是出于调试目的。当单元测试失败时,很高兴查看内部的实际数据以查看是否有任何问题或实际查看图像并查看它是否正确呈现。如果您创建一个 md5sum,如果出现问题,调试起来可能会有点困难。也许一个标志来启用它并在需要时禁用它是合适的。
  • 如果单元测试失败,无论如何你都必须调试......单元测试意味着快速并且经常重复(并且预计在 99% 或更多的情况下是“绿色”一旦您的代码开始工作,测试运行的数量......或者您是在 TDD 环境中执行此操作吗?)
  • 不,你是对的,单元测试绝对意味着快速和经常重复,所以我认为你的建议是完全有道理的(尤其是现在我们已经完全创建了所有的单元测试我们已经确认它们是准确的等)。我的建议是添加一个标志来启用调试模式,如果出现故障并且您需要更深入地挖掘,则不要为每条数据创建一个 md5sum。但是将默认标志设置为创建 md5sums 肯定会更有效。可能会在我们的应用程序的下一次迭代中做出这种改变。
【解决方案2】:

在单元测试中,您应该只测试您的单元,而不是第三方代码的单元。

您尚未指定有关图像调整器的任何详细信息,但我假设您正在使用第三方函数,这些函数算作它们自己的单元(一个函数是一个单元,就像一个类是一个单元一样)。

所以问题是:您的代码生成的二进制数据是您的单位吗?我猜不是,否则你会知道为什么二进制数据不同。

因为这些不是你的单元,所以不要为它们编写测试。相反,请转到原始单元来自(上游)的项目并检查他们的测试套件。

如果您关心集成测试(测试不同单元相互协作),您应该定义可以处理子组件返回的(不同)数据的稳定测试。例如。您可能需要进行图像比较(像素大小和像素值(以及文件格式可能)是否正确),而不是比较可能不同的二进制数据,因为文件格式通常允许不止一种方法来编码相同的图像数据(加上元数据)。

【讨论】:

  • 并模拟它,这样您就不必处理它的复杂性
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-18
相关资源
最近更新 更多