In one project I have found such lines of code:
protected function save($content, $path)
{
// ...
if (($handler = @fopen($path, 'w')) === false) {
throw new Exception('...');
}
// ...
if (@fwrite($handler, $content) === false) {
throw new Exception('...');
}
// ...
@fclose($handler);
}
I would like to test this method with PHPUnit, but I am a little bit stuck with correct test-case. If I will pass incorrect $path or a correct $path with incorrect permissions (e.g. 0444) then everything will stop at the first exception. If I pass correct $path with correct permissions than PHP will also be able to write to the file and the second exception won't be reached.
So is there any way to test the second exception without rewriting this method?
Or it is better to check both fopen and fwrite in one condition and use only one exception for both?
Or the best option is to separate this method into two - one for opening and one for writing - and test them separately?
The best way to achieve your goal is to use a mocked file system. I recommend to use vfsStream:
$ composer require mikey179/vfsStream
First of all I have to mention, that fread only returns false if you call this function with an invalid argument. If any other error occurs it will return the number of bytes that has been written. So you will have to add another check:
class SomeClass {
public function save($content, $path)
{
// ...
if (($handler = @fopen($path, 'w')) === false) {
throw new Exception('...');
}
$result = @fwrite($handler, $content);
// ...
if ($result === false) { // this will only happen when passing invalid arguments to fwrite
throw new Exception('...');
}
// ...
if ($result < strlen($content)) { // additional check if all bytes could have been written to disk
throw new Exception('...');
}
// ...
@fclose($handler);
}
}
The testcase for the method could look like this:
class SomeClassTest extends \PHPUnit_Framework_TestCase {
/**
* @var vfsStreamDirectory
*/
private $fs_mock;
/**
* @var vfsStreamFile
*/
private $file_mock;
/**
* @var $sut System under test
*/
private $sut;
public function setUp() {
$this->fs_mock = vfsStream::setup();
$this->file_mock = new vfsStreamFile('filename.ext');
$this->fs_mock->addChild($this->file_mock);
$this->sut = new SomeClass();
}
public function testSaveThrowsExceptionOnMissingWritePermissionOnFile() {
$this->expectException(\Exception::class);
$this->file_mock->chmod(0);
$this->sut->save(
'content',
$this->file_mock->url()
);
}
public function testSaveThrowsExceptionOnMissingWritePermissionOnDirectory() {
$this->expectException(\Exception::class);
$this->fs_mock->chmod(0);
$this->sut->save(
'content',
$this->fs_mock->url().'/new_file.ext'
);
}
public function testSaveThrowsExceptionOnInvalidContentType() {
$this->expectException(\Exception::class);
$this->fs_mock->chmod(0);
$this->sut->save(
$this,
$this->file_mock->url()
);
}
public function testSaveThrowsExceptionOnDiskFull() {
$this->expectException(\Exception::class);
$this->fs_mock->chmod(0777); // to be sure
$this->file_mock->chmod(0777); // to be sure
vfsStream::setQuota(1); // set disk quota to 1 byte
$this->sut->save(
'content',
$this->file_mock->url()
);
}
}
I hope I could help...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With