Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit: assertFileEquals() fails

Tags:

php

phpunit

I am developing a PHP software that creates thumbnails from images.

Now I need to make sure that thumbnails are created successfully, in other words that the initial image has been resized/cropped correctly.

I think there's only one way to do this: I manually create the thumbnail to compare with the thumbnail created by the software.

But how to test?

If I use assertFileEquals() to compare the thumbnail created by me and the one created by the software, of course the test fails, even if the two images are identical.

I imagine that happening if only because the creation date of the two files is different, or for similar reasons.

So, how to do?

like image 647
Mirko Pagliai Avatar asked Oct 06 '16 11:10

Mirko Pagliai


People also ask

What is PHPUnit testing?

PHPUnit is a unit testing framework for the PHP programming language. It is an instance of the xUnit design for unit testing systems that began with SUnit and became popular with JUnit. Even a small software development project usually takes hours of hard work.

What is assertion in PHPUnit?

The assertSame() function is a builtin function in PHPUnit and is used to assert whether the actually obtained value is the same as the expected value or not. This assertion will return true in the case if the expected value is the same as the actual value else returns false.

What is test case PHP?

To test a class in PHP, you'll create a test class named after that class. For example, if I had some sort of User class, the test class would be named UserTest . The test class, UserTest , will usually inherit the PHPUnit\Framework\TestCase class.


2 Answers

Storing a pair of source.png and expected_result.png (generated once by the software, verified as good and stored as the reference image) will suffice. Implementing a comparison function seems to be an overhead.

The main purpose of the unit tests is to signalize if system behavior changes, and that's what such test going to do if newly created thumbnail won't match with the reference one.

Yet, if for whichever reason software generates slightly different images every time, then, in case it's not a bug, use the suggested compare similar images approach.

What if image contents differ

In case of PNG files used in this example their contents might contain some auxiliary info such as EXIF.

So you might have to try creating a copy image without this additional info. Please verify if the following code works for you:

public function testThumbnails()
{
    $this->assertPngImageContentsEquals(__DIR__ . '/test1.png', __DIR__ . '/test2.png');
}

public static function assertPngImageContentsEquals(
    $expected,
    $actual,
    $message = 'Contents of PNG files differ'
)
{
    self::assertFileExists($expected, $message);
    self::assertFileExists($actual, $message);

    $copy_expected = self::_makePngCopy($expected, __DIR__ . '/expected.png');
    $copy_actual = self::_makePngCopy($actual, __DIR__ . '/actual.png');

    var_dump($copy_expected);
    var_dump($copy_actual);

    self::assertFileEquals($copy_expected, $copy_actual, 'Thumbnails differ');

    unlink($copy_expected);
    unlink($copy_actual);
}

private static function _makePngCopy($sourceFile, $resultFile)
{
    $image = imagecreatefrompng($sourceFile);
    imagepng($image, $resultFile);
    imagedestroy($image);
    return $resultFile;
}
like image 89
BVengerov Avatar answered Oct 08 '22 16:10

BVengerov


If assertFileEquals is failing, then there is something different between the two files. The internal code invokes file_get_contents on both files and asserts true if there are zero differences (so creation date is not part of the assertion).

Since you are manually creating the thumbnail, there must be slight differences. Instead you would need to do a "mostly the same" comparison, there are two questions related to coding this:

  • Compare 2 images in php
  • Similar images - how to compare them

Then decide how much difference is considered a pass. So you would do the "mostly the same comparison", then use asserts to determine if the answer of the "mostly the same" comparison falls within a range you can accept.

Update

I ran a quick test to ensure that assertFileEquals works properly on a binary file:

class FileEqualsTest extends PHPUnit_Framework_TestCase {

public function test_yes_no_answer() {

    file_put_contents("a.txt","\e[0m");
    file_put_contents("b.txt","\e[0m");
    file_put_contents("c.txt","\e[30m");

    // straight get contents and comparisons
    $contentsA = file_get_contents("a.txt");
    $contentsB = file_get_contents("b.txt");
    $this->assertEquals($contentsA, $contentsB);

    $contentsC = file_get_contents("c.txt");
    $this->assertNotEquals($contentsA, $contentsC);

    // using file equals has same answer
    $this->assertFileEquals("a.txt","b.txt");
    $this->assertFileNotEquals("a.txt","c.txt");

}

..and it worked as expected on a very small scale. So it would seem there is some tiny difference in some way. You could try the options shown in the other questions above to see if there is a tiny difference, if that is important to your testing.

like image 36
Katie Avatar answered Oct 08 '22 18:10

Katie