[ACCEPTED]-How do you use PHPUnit to test a function if that function is supposed to kill PHP?-phpunit

Accepted answer
Score: 29

It's obviously an old question but my suggestion 9 would be to move the code that die()'s into a 8 separate method that you can then mock.

As 7 an example, instead of having this:

class SomeClass
{
    public function do()
    {
        exit(1);
        // or
        die('Message');
    }
}

do this:

class SomeClass
{
    public function do()
    {
        $this->terminate(123);
        // or
        $this->terminate('Message');
    }

    protected function terminate($code = 0)
    {
        exit($code);
    }

    // or 
    protected function terminate($message = '')
    {
        die($message);
    }
}

That 6 way you can easily mock the terminate method and 5 you don't have to worry about the script 4 terminating without you being able to catch 3 it.

Your test would look something like this:

class SomeClassTest extends \PHPUnit_Framework_TestCase
{

    /**
     * @expectedExceptionCode 123
     */
    public function testDoFail()
    {
        $mock = $this->getMock('SomeClass');
        $mock->expects($this->any())
             ->method('terminate')
             ->will($this->returnCallback(function($code) {
                 throw new \Exception($code);
             }));

        // run to fail
        $mock->do();
    }
}

I 2 haven't tested the code but should be pretty 1 close to a working state.

Score: 27

As every tests are run by the same PHPUnit 16 process, if you use exit/die in your PHP 15 code, you will kill everything -- as you 14 noticed ^^

So, you have to find another solution, yes 13 -- like returning instead of dying ; or 12 throwing an exception (you can test if some tested code has thrown an expected exception).

Maybe PHPUnit 3.4 11 and it's --process-isolation switch (see Optionally execute each test using a separate PHP process) might help (by not having everything dying), but you 10 still wouldn't be able to get the result 9 of the test, if PHPUnit doesn't get the 8 control back.

I've had this problem a couple 7 of times ; solved it by returning instead 6 of dying -- even returning several times, if 5 needed, to go back "high enough" in 4 the call stack ^^
In the end, I suppose 3 I don't have any "die" anymore 2 in my application... It's probably better, when 1 thinking about MVC, btw.

Score: 14

There's no need to change the code just 2 to be able to test it, you can simply use 1 set_exit_overload() (provided by test_helpers from same author as PHPUnit).

Score: 7

I realise you've already accepted an answer 15 for this and it's an old question, but I 14 figure this might be useful for someone, so 13 here goes:

Instead of using die(), you could use 12 throw new RuntimeException() (or an exception class of your own), which 11 will also halt program execution (albeit 10 in a different fashion) and use PHPUnit's 9 setExpectedException() to catch it. If you want your script to 8 die() when that exception is encountered, printing 7 absolutely nothing up at level of the user, take 6 a look at set_exception_handler().

Specifically, I'm thinking of 5 a scenario in which you'd place the set_exception_handler()-call 4 into a bootstrap file that the tests don't 3 use, so the handler won't fire there regardless 2 of scenario, so nothing interferes with 1 PHPUnit's native exception handling.

Score: 5

This relates to set of issues I've been 7 having getting some legacy code to pass 6 a test. So I've come up with a Testable 5 class like this...

class Testable {
   static function exitphp() {
      if (defined('UNIT_TESTING')) {
         throw new TestingPhpExitException();
      } else {
         exit();
      }
   }
}

Now I simply replace calls 4 to exit() with Testable::exitphp().

If it's 3 under test I just define UNIT_TESTING, in 2 production I don't. Seems like a simple 1 Mock.

Score: 0

You can kill the script or throw an exception, depending 6 on the value of an environmental variable...

So 5 you kill in production or throw an exception 4 in test environment.

Any call to die or exit, Kills 3 the whole process...

This was supposed to 2 be a comment but I can't comment with the 1 level of my reputation points.

More Related questions