views:

214

answers:

3

I'm testing some legacy code that extends the default php exception object. This code prints out a custom HTML error message.

I would like to mock this exception object in such a way that when the tested code generates an exception it will just echo the basic message instead of giving me the whole HTML message.

I cannot figure out a way to do this. It seems like you can test for explicit exceptions, but you can't change in a general way the behavior of an exception, and you also can't mock up an object that extends a default php functionality. ( can't think of another example of this beyond exceptions... but it would seem to be the case )

I guess the problem is, where would you attach the mocked object?? It seems like you can't interfere with 'throw new' and this is the place that the object method is called....

Or if you could somehow use the existing phpunit exception functionality to change the exception behavior the way you want, in a general way for all your code... but this seems like it would be hacky and bad....

EDIT: here is some code to make things clearer:

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{
 ...

so, my question, is there a way to deal with this overriden class, without doing it on a case by case basis? what if I'm not testing the behavior of the exception, just the code that causes the exception?

A: 

The extened PHP exception object "prints" a costum HTML error page? You mean its error message is an entire HTML page? That's not very clever...

What you can do about it is to replace the default exception handler (see this function), call getMessage on the exception and parse the HTML error page to extract the message. Then you can print the error message and kill the script. Like this (in PHP 5.3):

set_exception_handler(
    function (Exception $e) {
        die(parse_html_error_page($e->getMessage()));
    }
);
Artefacto
well, the script processes the error in some minor ways before it includes an HTML file for output to the user, with a 'pretty' formatted message. I agree that this possibly wasn't the most modular approach....I don't think this will work, though, because this error handling class is serving the message for errors that were caught within the script. set_error_handler only works for errors that weren't caught....
awongh
A: 

OK, I misunderstood the question. If the script you're testing catches the error and then echoes an error page, then this has nothing to do with exceptions. You can use the ob_ family:

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();
Artefacto
I should have included some code or pseudo code to make it more clear, but I don't think this will work either: this thread says that you will still see thrown exceptions even while you buffer the output.... http://stackoverflow.com/questions/2201841/how-do-i-stop-php-output-buffering-from-eating-error-messagesAnd after I dove further into the code, it also looks like the errors are originating from more places than I originally thought.... I think maybe I just wrote a poorly defined question....
awongh
You would maybe see the thrown exceptions if they are not caught and the exception handler spits an error message and kills the script. I'm not sure if that's the behavior of the default exception handler, but even if it is, it does not apply when the exception is caught.
Artefacto
A: 

I would first write a test that captures the exception generation behavior:

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.');
}

Now you can do several things with this coverage test. You can either fix up the exception, or fix the code that causes the exception.

Another thing you can do is wrap the entire file.php in a class:

 class FooClass {

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

    }   

}

Then add tests while using extract method until you isolate exception.

[EDIT]

Here is some serious procedural legacy code:

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

function countNewMessages($user_id) {
}

function countNewOrders() {
}

function countNewReturns() {
}

function getDB($init = NULL) {
}

function getDisplay() {
}

getDisplay();

?>

And here is the wrapped class:

<?php
require_once '';  //helper file

class Displayer {
    function countNewMessages($user_id) {
    }

    function countNewOrders() {
    }

    function countNewReturns() {
    }

    function getDB($init = NULL) {
    }

    function getDisplay() {
    }
}
?>

And now I can test it:

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

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

And test the individual functions in it. And if I can further sprout methods on it.

The above test would be considered a coverage test. There may be bugs in it, but that is what it does. So as I sprout methods the get more code coverage from tests by sprouting that I can make sure I don't break the output.

Gutzofter
can you explain more about your second example? what would the tests look like? You would do $foo_instance = new FooClass ... then capture ... $foo_instance->runFoo() ... inside a test??
awongh
This is something I got from Michael Feather's Book WEWLC. It's all an object any way. See my edit.
Gutzofter