Как мне написать модульные тесты на PHP с процедурной кодовой базой?

StackOverflow https://stackoverflow.com/questions/899390

Вопрос

Я в основном убежден в преимуществах модульного тестирования, и я хотел бы начать применять концепцию к большой существующей кодовой базе, написанной на PHP.Менее 10% этого кода является объектно-ориентированным.

Я просмотрел несколько фреймворков модульного тестирования (PHPUnit, SimpleTest и phpt).Однако я не нашел примеров ни для одного из них, которые тестировали бы процедурный код.Какой фреймворк лучше всего подходит для моей ситуации и есть ли какие-либо примеры модульного тестирования PHP с использованием кода, отличного от ООП?

Это было полезно?

Решение

Вы можете модульно протестировать процедурный 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) или возвращают результат напрямую.

Передаются ли переменные явно, как параметры или массивы параметров между функциями?Или переменные задаются во многих разных местах и передаются неявно как глобальные?Если это (хороший) явный случай, вы можете выполнить модульное тестирование функции, (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);
    }

Надеюсь, это поможет.

Другие советы

Что модульные тесты делают хорошо, и для чего вам следует их использовать, так это когда у вас есть фрагмент кода, в который вы вводите некоторое количество входных данных, и вы ожидаете получить некоторое количество выходных данных обратно.Идея заключается в том, что, когда вы добавите функциональность позже, вы сможете запустить свои тесты и убедиться, что она по-прежнему выполняет старую функциональность таким же образом.

Итак, если у вас есть процедурная кодовая база, вы можете выполнить это, вызывая свои функции в тестовых методах

require 'my-libraries.php';
class SomeTest extends SomeBaseTestFromSomeFramework {
    public function testSetup() {
        $this->assertTrue(true);
    }

    public function testMyFunction() {
        $output = my_function('foo',3);

        $this->assertEquals('expected output',$output);
    }
}

Этот трюк с кодовыми базами PHP заключается в том, что часто код вашей библиотеки будет мешать работе вашей тестовой платформы, поскольку ваша кодовая база и тестовые платформы будут содержать много кода, связанного с настройкой среды приложения в веб-браузере (сеанс, общие глобальные переменные и т.д.).Ожидайте, что потратите некоторое время на то, чтобы добраться до точки, где вы сможете включить свой библиотечный код и запустить очень простой тест (функция TestSetup выше).

Если ваш код не имеет функций и представляет собой просто серию PHP-файлов, которые выводят HTML-страницы, вам отчасти не повезло.Ваш код не может быть разделен на отдельные блоки, что означает, что модульное тестирование не принесет вам большой пользы.Вам было бы лучше потратить свое время на уровне "приемочного тестирования" с такими продуктами, как Селен и Ватир.Это позволит вам автоматизировать работу браузера, а затем проверять страницы на наличие содержимого в определенных местах / в формах.

Вы могли бы попытаться включить свой не-ооп код в тестовый класс, используя

require_once 'your_non_oop_file.php' # Contains fct_to_test()

И с помощью PHPUnit вы определяете свою тестовую функцию :

testfct_to_test() {
   assertEquals( result_expected, fct_to_test(), 'Fail with fct_to_test' );
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top