I had a method, that opened a socket connection, used, and then closed it. In order to make it testable, I moved the dealing with the connection to separate methods (see the code below).
Now I want to write a unit test for the barIntrefaceMethod() and need to mock the method openConnection(). With other words, I need a fake resource.
Is it possible / How to "manually" create a variable of the type resource in PHP (in order to fake handles like "opened files, database connections, image canvas areas and the like" etc.)?
FooClass
class FooClass
{
public function barIntrefaceMethod()
{
$connection = $this->openConnection();
fwrite($connection, 'some data');
$response = '';
while (!feof($connection)) {
$response .= fgets($connection, 128);
}
return $response;
$this->closeConnection($connection);
}
protected function openConnection()
{
$errno = 0;
$errstr = null;
$connection = fsockopen($this->host, $this->port, $errno, $errstr);
if (!$connection) {
// TODO Use a specific exception!
throw new Exception('Connection failed!' . ' ' . $errno . ' ' . $errstr);
}
return $connection;
}
protected function closeConnection(resource $handle)
{
return fclose($handle);
}
}
Resource mocking requires some magic.
Most of I/O functions allows to use a protocol wrappers. This feature used by vfsStream to mock the file system. Unfortunately the network functions such as
fsockopen()don't support it.But you can to override the function. I don't consider the Runkit and APD, you can do it without PHP extensions.
You create a function with same name and custom implementation in the current namespace. This technique is described in another answer.
Also the Go! AOP allows to override any PHP function in most cases. Codeception/AspectMock uses this feature to functions mocking. The Badoo SoftMocks also provides this functionality.
In the your example you can completely override
fsockopen()by any method and use vfsStream to call thefgets(),fclose()and other I/O functions. If you don't want to test theopenConnection()method you can mock it to setup the vfsStream and return the simple file resource.