Ответ 1
Вы можете модульно тестировать процедурный PHP, без проблем. И вам определенно не повезло, если ваш код смешивается с HTML.
На уровне приложения или приемочного тестирования ваш процедурный PHP, вероятно, зависит от значения суперглобалов ($_POST, $_GET, $_COOKIE
и т.д.) для определения поведения и заканчивается включением файла шаблона и выплевыванием вывода.
Чтобы выполнить тестирование на уровне приложения, вы можете просто установить суперглобальные значения; запустите выходной буфер (чтобы сохранить кучу html от наводнения вашего экрана); вызвать страницу; утверждать против вещей внутри буфера; и уничтожить буфер в конце. Итак, вы можете сделать что-то вроде этого:
public function setUp()
{
if (isset($_POST['foo'])) {
unset($_POST['foo']);
}
}
public function testSomeKindOfAcceptanceTest()
{
$_POST['foo'] = 'bar';
ob_start();
include('fileToTest.php');
$output = ob_get_flush();
$this->assertContains($someExpectedString, $output);
}
Даже для огромных "фреймворков" с большим количеством включений такой тип тестирования скажет вам, есть ли у вас функции уровня приложения, работающие или нет. Это будет очень важно, когда вы начнете совершенствовать свой код, потому что даже если вы уверены, что соединитель базы данных все еще работает и выглядит лучше, чем раньше, вам нужно нажать кнопку и увидеть, что да, вы все равно можете войти и выйти из базы данных.
На более низких уровнях существуют незначительные вариации в зависимости от области видимости переменной, и работают ли функции по побочным эффектам (возврат true или false) или прямое возвращение результата.
Являются ли переменные явно переданы в качестве параметров или массивов параметров между функциями? Или переменные заданы во многих разных местах и передаются неявно как глобальные? Если это (хороший) явный случай, вы можете unit test использовать функцию (1), включая файл, содержащий функцию, затем (2) напрямую подать значения тестовой функции и (3) захватить вывод и утвердить его. Если вы используете глобальные переменные, вам просто нужно быть очень осторожным (как указано выше, в примере $_POST), чтобы тщательно исключить все глобальные переменные между тестами. Это также особенно полезно для того, чтобы держать тесты очень маленькими (5-10 строк, 1-2 утверждения) при работе с функцией, которая толкает и тянет много глобалов.
Еще одна основная проблема заключается в том, работают ли функции путем возврата вывода или путем изменения переданных параметров, возвращая true/false. В первом случае тестирование проще, но, опять же, это возможно в обоих случаях:
// assuming you required the file of interest at the top of the test file
public function testShouldConcatenateTwoStringsAndReturnResult()
{
$stringOne = 'foo';
$stringTwo = 'bar';
$expectedOutput = 'foobar';
$output = myCustomCatFunction($stringOne, $stringTwo);
$this->assertEquals($expectedOutput, $output);
}
В плохом случае, когда ваш код работает по побочным эффектам и возвращает true или false, вы все равно можете довольно легко протестировать:
/* suppose your cat function stupidly
* overwrites the first parameter
* with the result of concatenation,
* as an admittedly contrived example
*/
public function testShouldConcatenateTwoStringsAndReturnTrue()
{
$stringOne = 'foo';
$stringTwo = 'bar';
$expectedOutput = 'foobar';
$output = myCustomCatFunction($stringOne, $stringTwo);
$this->assertTrue($output);
$this->Equals($expectedOutput, $stringOne);
}
Надеюсь, что это поможет.