Search code examples
phpunit-testingsymfonyphpunitsonata

PHPUnit test a function that write in file and check the content into created file


I am contributing to sonata/exporter, a library used for export data in many formats (CSV, JSON, XML, XLS, ...).

I work on a Writer that converts boolean values into strings (e.g. yes/no) by encapsulating another Writer (like CsvWriter or XlsWriter).

It's my first experience with phpunit.

All unit tests made on the existing Writers use this logic :
- Create a file.
- Write data in file using the corresponding format.
- Make an assertEquals on file_get_contents(filename).

So, I've written this test :

public function setUp()
{
    $this->filename = 'formatedbool.xls';
    $this->sampleWriter = new XlsWriter($this->filename, false);
    $this->trueLabel = 'oui';
    $this->falseLabel = 'non';

    if (is_file($this->filename)) {
        unlink($this->filename);
    }
}

public function testValidDataFormat()
{
    $writer = new FormatedBoolWriter($this->sampleWriter, $this->trueLabel, $this->falseLabel);
    $writer->open();
    $writer->write(array('john', 'doe', false, true));
    $writer->close();

    $expected = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta name=ProgId content=Excel.Sheet><meta name=Generator content="https://github.com/sonata-project/exporter"></head><body><table><tr><td>john</td><td>doe</td><td>non</td><td>oui</td></tr></table></body></html>';
    $this->assertEquals($expected, trim(file_get_contents($this->filename)));
}

When submitting my PR, the owner says me :

just use a mock with expected method call and check calling argument, this will avoid creating the file. see https://phpunit.de/manual/current/en/test-doubles.html#test-doubles.mock-objects.examples.with-consecutive.php

I have begin to rewrite tests using a Mock but I have an error on file_get_contents because file is not created.

The "write" method just write in a file and return nothing.

I think he want I test the data after converting bools, but before writing in file. How can I check the result of the file content without really create it ? Or simply access to my $data during the method call ?

EDIT Thanks to @Cerad, the code I've submitted :

public function testValidDataFormat()
{
    $data = array('john', 'doe', false, true);
    $expected =  array('john', 'doe', 'no', 'yes');
    $mock = $this->getMockBuilder('Exporter\Writer\XlsWriter')
                   ->setConstructorArgs(array('formattedbool.xls', false))
                   ->getMock();
    $mock->expects($this->any())
           ->method('write')
           ->with($this->equalTo($expected));
    $writer = new FormattedBoolWriter($mock, $this->trueLabel, $this->falseLabel);
    $writer->open();
    $writer->write($data);
    $writer->close();
}

I'm waiting for answer of the project owner.

EDIT PR merged at https://github.com/sonata-project/exporter/pull/56


Solution

  • This question has been answered by @Cerad by commenting on the question.

    The PR has been accepted and merged, see https://github.com/sonata-project/exporter/pull/56