📜 ⬆️ ⬇️

Namespaces + PHPUnit = 100% test coverage

I have long wanted to share with the public a way to test code that uses functions for working with the external environment: sockets, databases, files, and anything else. Today, after seeing the article Runkit + PHPUnit = 100% test coverage , I decided that now is the time.
The solution with Runkit is beautiful, but there is one problem - Runkit does not spread along with PHP, it must be installed separately. I want to suggest an approach that works in the usual delivery of PHP 5.3+, on one condition - the project must use namespaces.

Idea



The idea is very simple and is based on the name resolution rules in PHP : the called function is first searched in the current namespace, and only then the built-in PHP function is called. For example, in the following piece of code:
')
namespace A;
foo();


PHP will first try to call A \ foo () and only then foo (). So, if we declare a function with the name, say, “fsockopen” in the namespace of the project, then it will be the first to be called.

Application



Suppose we have this class:

src / MyClass.php
<?php
namespace MyNS;

class MyClass
{
public function someMethod()
{
$fp = fsockopen( 'example.org' , 123);
}
}


* This source code was highlighted with Source Code Highlighter .


To override the fsockopen function, create the following file in the tests:

tests / helpers.php
<?php
namespace MyNS;

function fsockopen($hostname, $port)
{
$GLOBALS[ 'fsockopen' ] = array($hostname, $port);
}

* This source code was highlighted with Source Code Highlighter .


Now you can write this test:

tests / MyClass_Test.php
<?php
namespace MyNS\Tests;
use PHPUnit_Framework_TestCase;
use MyNS\MyClass;

require 'helpers.php' ;
require '../src/MyClass.php' ;

class MyClass_Test extends PHPUnit_Framework_TestCase
{
public function test_someMethod()
{
$test = new MyClass();
$test->someMethod();
$ this ->assertEquals(array( 'example.org' , 123), $GLOBALS[ 'fsockopen' ]);
}
}


* This source code was highlighted with Source Code Highlighter .


In this test, not the built-in fsockopen will be called, but declared in helpers.php.

Of course, the $ GLOBALS option is not the only one possible, and is shown here only for simplicity. What I propose is not a ready-made solution, but only an approach that everyone can adapt to their needs.

Source: https://habr.com/ru/post/124933/


All Articles