Ignore exit () and die () with PHPUnit

First of all, the name suggests that this is a duplicate of this or that , but for several reasons, these answers do not work for me, even if my original problem is the same. I will explain why.

My problem is this: I have several cases in my code where I want to send the header and body, and then complete the processing. Unlike other questions, I cannot use return or throw an exception instead (these are obviously different functions intended for different purposes than exit, and this is not an error, but just an early completion in some specific cases).

However, I want to write unit tests that run these methods, make sure the appropriate headers are installed (the solution is found here ), the output body is correct (solved using the $this->expectOutputString() method in the test case), and then continue testing. Between them will exit .

I tried @runInSeparateProcess -nnotation in PHPUnit, I also checked the test_helpers extension, which works, but I don’t want to add another extension (keep in mind that tests will also be run during production) for one line of native PHP code that breaks everything . There should be an easier way without sacrificing best practices.

Does anyone have a good solution to this problem?

+6
source share
2 answers

I added a variable to bootstrap that I could reference in IF code in those rare cases that I don't need to exit.

 define ('PHPUNIT_RUNNING', 1); 

Normal program:

 if(! @PHPUNIT_RUNNING === 1 ) { exit; } 

PHPUnit is not defined as a rule, so there is a warning generated when executing PHP (which we hide with @. Then the code will do what we want when not in test mode. This was added after the main code was written when we added testing PHPUnit in an existing project instead of doing TDD.

Note:

We make it as economical as possible in order to solve the obsolescence problem, otherwise we do what others suggested and throw exceptions or return data to parent functions.

+3
source

I just tested the following idea:

ExitException.php:

 <?php class DieException extends Exception {} // for those people who like die as well as exit class ExitException extends Exception {} 

entrypoint.php:

 <?php require_once 'ExitException.php'; try { require 'main_code.php'; run_main_code(); } catch (DieException $e) { return $e->getMessage(); } catch (ExitException $e) { return $e->getMessage(); } 

A few include later:

deepcode.php

 <?php throw new ExitException('Exiting normally'); 

This models exit or die , which falls to the highest level. Your program seems to come out as before, and now you can test it without killing the entire test suite. The only thing you got is that you will also catch another regular Exception in your existing code, in which case you will have to change your code to rebuild the DieException / ExitException tags until they reach the top level.

Another alternative is to return purely, which is probably due to rewriting a lot of your code. If you do not exit at this moment, why will your program generate additional results? He should check as early as possible if an "early exit" is required, and then just call this code and go to the natural end of the program.

This problem becomes much more complicated if you have to deal with third-party libraries or other code that you should not or cannot change, but if they do not come with your own unit tests, there are no tests for writing values ​​for because ideally you should not Change third-party code to avoid future compatibility issues. A well-written third-party library should never die . It should always return control to the caller or throw an Exception that can be caught.

+2
source

Source: https://habr.com/ru/post/969985/


All Articles