Pull to refresh

Пространства имён + PHPUnit = 100% покрытие тестами

Reading time 2 min
Views 3.4K
Давно хотел поделиться с общественностью способом тестировать код, использующий функции для работы с внешней средой: с сокетами, БД, файлами и чем угодно ещё. Сегодня, увидев статью Runkit + PHPUnit = 100% покрытие тестами, решил, что сейчас самое время.
Решение с Runkit красивое, но есть одна проблема — Runkit не распространяется вместе PHP, его надо ставить отдельно. Я же хочу предложить подход, работающий в обычной поставке PHP 5.3+, при одном условии — проект должен использовать пространства имён.

Идея



Идея очень проста и основывается на правилах разрешения имён в PHP: вызванная функция сначала ищется в текущем пространстве имён, и только потом вызывается встроенная функция PHP. Например, в следующем куске кода:

namespace A;
foo();


PHP сначала попытается вызывать A\foo() и только потом foo(). Значит, если мы объявим функцию с именем, скажем, «fsockopen» в пространстве имён проекта, то вначале вызвана будет именно она.

Применение



Предположим, у нас есть вот такой класс:

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.


Чтобы перекрыть функцию fsockopen, создаём в тестах такой вот файл:

tests/helpers.php
<?php
namespace MyNS;

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

* This source code was highlighted with Source Code Highlighter.


Теперь можно написать такой тест:

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.


В этом тесте будет вызвана не встроенная fsockopen, а объявленная в helpers.php.

Конечно же вариант с $GLOBALS не единственный возможный, и показан здесь только для простоты. То, что предлагаю — это не готовое решение, а лишь подход, который каждый может приспособить под свои нужды.
Tags:
Hubs:
+31
Comments 15
Comments Comments 15

Articles