phpUnit — фиктивный объект расширенного исключения php

Я тестирую некоторый устаревший код, который расширяет объект исключения php по умолчанию. Этот код выводит пользовательское сообщение об ошибке в формате HTML.

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

Я не могу понять, как это сделать. Похоже, вы можете протестировать явные исключения, но вы не можете изменить поведение исключения в целом, и вы также не можете смоделировать объект, который расширяет функциональные возможности php по умолчанию. (не могу придумать другого примера этого, кроме исключений... но, похоже, это так)

Я думаю, проблема в том, куда бы вы прикрепили издевательский объект ?? Кажется, что вы не можете мешать «бросить новый», и это место, где вызывается метод объекта....

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

РЕДАКТИРОВАТЬ: вот некоторый код, чтобы прояснить ситуацию:

class FooTest extends PHPUnit_Framework_TestCase{

    public function testBar(){
        include '/path/to/file.php'; //generates exception

        $this->assertTrue($baz);             
    }
}
 ...
//overridden exception class
class Foo_Exception extends ErrorException{
 ...

Итак, мой вопрос, есть ли способ справиться с этим переопределенным классом, не делая это в каждом конкретном случае? что, если я не проверяю поведение исключения, а только код, вызывающий исключение?


person awongh    schedule 14.05.2010    source источник
comment
Хорошо, теперь я запутался. Либо исключение во включении не перехвачено, и тогда мой первый ответ остается в силе, либо оно перехвачено, и мой второй ответ остается в силе. Тип исключения не имеет значения.   -  person Artefacto    schedule 15.05.2010
comment
вы правы... Я был сбит с толку тем, как ob_start будет обрабатывать вещи... Однако... ваше решение действительно работает, чтобы подавить сообщение об ошибке, но это также означает, что оно обрабатывает все выходные данные одинаково... Думаю, я был спрашивая о более конкретном решении для работы с самим классом исключений.... но теперь, когда я все это обдумал, это кажется неосуществимым... или обязательно желательным... Я думаю, лучший случай для работы с поведением объекта заключается в возбуждении исключений для каждого случая. Иногда вещи имеют смысл только тогда, когда вы задаете расплывчатый вопрос....   -  person awongh    schedule 15.05.2010


Ответы (3)


Я бы сначала написал тест, который фиксирует поведение генерации исключений:

include '/path/to/file.php'; //generates exception
public function testCatchFooException() {
    try {
        $this->assertTrue($baz);             
    }
    catch (Exception $expected) {
        $this->assertEquals('This is expected html from exception', $expected->getMessage());
        return;
    }

    $this->fail('An expected Exception has not been raised Foo_Excpetion.');
}

Теперь вы можете сделать несколько вещей с этим тестом покрытия. Вы можете либо исправить исключение, либо исправить код, вызывающий исключение.

Еще одна вещь, которую вы можете сделать, это обернуть весь file.php в класс:

 class FooClass {

    function runFoo() {
        include '/path/to/file.php'; //generates exception

    }   

}

Затем добавляйте тесты при использовании метода извлечения, пока не изолируете исключение.

[ИЗМЕНИТЬ]

Вот серьезный процедурный устаревший код:

<?php
require_once 'helper.php';  //helper file

function countNewMessages($user_id) {
}

function countNewOrders() {
}

function countNewReturns() {
}

function getDB($init = NULL) {
}

function getDisplay() {
}

getDisplay();

?>

И вот упакованный класс:

<?php
require_once '';  //helper file

class Displayer {
    function countNewMessages($user_id) {
    }

    function countNewOrders() {
    }

    function countNewReturns() {
    }

    function getDB($init = NULL) {
    }

    function getDisplay() {
    }
}
?>

И теперь я могу проверить это:

    function testGetDisplay() {
    $display = new Displayer();

    $this->assertEquals('html code', $display->getDisplay());
}

И проверить отдельные функции в нем. И если я смогу дальше прорасти методы на нем.

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

person Gutzofter    schedule 15.05.2010
comment
Можете ли вы объяснить больше о вашем втором примере? как будут выглядеть тесты? Вы бы сделали $foo_instance = new FooClass... затем зафиксировали... $foo_instance->runFoo()... внутри теста?? - person awongh; 15.05.2010
comment
Это то, что я почерпнул из книги Майкла Фезера WEWLC. В любом случае это объект. Смотрите мою правку. - person Gutzofter; 15.05.2010

Расширенный объект исключения PHP «печатает» HTML-страницу с ошибкой костюма? Вы имеете в виду, что его сообщение об ошибке представляет собой целую HTML-страницу? Это не очень умно...

Что вы можете с этим сделать, так это заменить обработчик исключений по умолчанию (см. эта функция), вызовите getMessage для исключения и проанализируйте HTML-страницу с ошибкой, чтобы извлечь сообщение. Затем вы можете распечатать сообщение об ошибке и убить скрипт. Вот так (в PHP 5.3):

set_exception_handler(
    function (Exception $e) {
        die(parse_html_error_page($e->getMessage()));
    }
);
person Artefacto    schedule 14.05.2010
comment
Что ж, сценарий обрабатывает ошибку некоторыми второстепенными способами, прежде чем включить HTML-файл для вывода пользователю с «красивым» отформатированным сообщением. Я согласен, что это, возможно, был не самый модульный подход... Однако я не думаю, что это сработает, потому что этот класс обработки ошибок обслуживает сообщение об ошибках, которые были обнаружены в сценарии. set_error_handler работает только с ошибками, которые не были обнаружены.... - person awongh; 14.05.2010

Хорошо, я неправильно понял вопрос. Если тестируемый скрипт перехватывает ошибку, а затем выводит страницу с ошибкой, то это не имеет ничего общего с исключениями. Вы можете использовать семейство ob_:

ob_start();
include $file;
$contents = ob_get_contents();

if (result_is_error($contents))
    die(extract_error_from_result($contents));
else
    echo $contents;

ob_end_clean();
person Artefacto    schedule 14.05.2010
comment
Я должен был включить некоторый код или псевдокод, чтобы сделать его более понятным, но я не думаю, что это тоже сработает: этот поток говорит, что вы все равно будете видеть выброшенные исключения, даже когда вы буферизуете вывод.... stackoverflow.com/questions/2201841/ И после того, как я углубился в код, похоже, что ошибки возникают из большего количества мест, чем я первоначально думал... Я думаю, может быть, я просто написал плохо определенный вопрос.... - person awongh; 15.05.2010
comment
Возможно, вы увидите выброшенные исключения, если они не перехвачены, а обработчик исключений выдает сообщение об ошибке и убивает скрипт. Я не уверен, что это поведение обработчика исключений по умолчанию, но даже если это так, оно не применяется при перехвате исключения. - person Artefacto; 15.05.2010