, (*1)
, (*2)
Mockable native static functions for PHP., (*3)
What is it?
Do you have a class method that calls a PHP native/built-in function like file_get_contents, which you then test by having to create a dummy file for it to ingest? Well, say hello to Parrot. Now you can inject the built-in File functions, along with many others as a dependency which you can mock out during tests., (*4)
Installation
composer require enzyme/parrot
Example
Let's take a look at what used to happen:, (*5)
Using the built in method.
class Foo
{
public function openConfig($file)
{
$contents = file_get_contents($file);
return $contents;
}
}
Testing..., (*6)
public function FooTest
{
$file = __DIR__ . '/actual_file.txt';
$expected = 'Contents of actual_file.txt';
$foo = new Foo;
$actual = $foo->openConfig($file);
$this->assertEquals($actual, $expected);
}
The problem with the above is, actual_file.txt needs to reside in your test folder, get shipped with your tests, have the correct permission etc... it's a hassle., (*7)
Now using Parrot.
use Enzyme\Parrot\File;
class Foo
{
protected $fileDispatch;
public function __construct(File $fileDispatch)
{
$this->fileDispatch = $fileDispatch;
}
public function openConfig($file)
{
$contents = $this->fileDispatch->getContents($file);
return $contents;
}
}
Testing..., (*8)
public function FooTest
{
$file = __DIR__ . '/fake_file.txt';
$expected = 'Contents of fake_file.txt';
$fileDispatch = m::mock('Enzyme\Parrot\File[getContents]', function ($mock) use ($expected, $file) {
$mock->shouldReceive('getContents')->withArgs([$file, []])->times(1)->andReturn($expected);
});
$foo = new Foo($fileDispatch);
$actual = $foo->openConfig($file);
$this->assertEquals($actual, $expected);
}
Now we just fake the file and it's contents, sweet!!!, (*9)
Sugar
You may have noticed in the above example that the Parrot version of file_get_contents was simply getContents()., (*10)
With all the Parrot'd wrappers around PHP's functions, we leave off the prefix. Who wants to repeat themselves?, (*11)
The function name rules.
-
If the original function name starts with a prefix like file_, f, curl_, imap_, mysql_ etc, you simply leave them off when using the equivalent class wrapper., (*12)
-
If the original name has an underscore in it, replace it with camelCase. So for example file_get_contents becomes getContents and mysql_affected_rows becomes affectedRows., (*13)
-
If the original name has a string of words, they are converted to camelCase too. For example imap_createmailbox becomes createMailbox., (*14)
-
If the original function, following the rules above now starts with a number, replace then number with it's spelt equivalent. For example imap_8bit becomes eightBit., (*15)
Wrappers
The follow wrappers are currently available:, (*16)
| Name |
Prefixes removed |
| Curl |
curl_ |
| File |
file, file_, f |
| Ftp |
ftp_ |
| Gz |
gz |
| Image |
image |
| Imap |
imap_ |
| MySql |
mysql_ |
| PostgreSql |
pg_ |
| Sqlite |
sqlite_ |
| Glob |
glob (Simply becomes execute) |
Missing something?
If there's a particular wrapper you're looking for and it isn't listed above, open a new issue, or simply extend Parrot following the rules in the existing wrappers and send a PR. Please check out CONTRIBUTING.md as well., (*17)