PHPUnit - Procedural code needing to be included multiple times

319 Views Asked by At

I am currently trying to build up a phpunit testsuite to test some ajax code which is written procedurally. I am unable to edit the original code, fooBar.php, because it might cause issues elsewhere. The issue occurs when I am trying to run a php file multiple times with different parameters; the code has a function which throws redeclare exceptions. Below is an example of what I am dealing with.

fooBar.php - php file hit with an ajax call

$foo = $_POST['bar'];

function randomFunctionName(){
    echo "randomFunctionName";
}

if($foo == "fooBar"){
     $jsonResponse = array('success'=>true);
}else{
     $jsonResponse = array('success'=>false);
}

echo json_encode($jsonResponse);

fooBarTest.php - phpunit test file

class fooBarTest extends \PHPUnit\Framework\TestCase
{   

   private function _execute() {
       ob_start();
       require 'fooBar.php';
       return ob_get_clean();
   }    

   public function testFooBarSuccess(){
       $_POST['bar'] = "fooBar";

       $response = $this->_execute();
       $this->assertTrue((strpos($response, 'success') !== false) && (strpos($response, 'true') !== false));

   }        
   public function testFooBarFailure(){
       $_POST['bar'] = "notFooBar";

       $response = $this->_execute();
       $this->assertTrue((strpos($response, 'success') !== false) && (strpos($response, 'false') !== false));

   }

So when I run this test, I get the following error

PHP Fatal error:  Cannot redeclare randomFunctionName() (previously declared in.......

The problem is coming from the fact that fooBar.php is technically already there when the second test, testFooBarFailure(), is ran. As you can see though, I need to rerun fooBar.php in order to get a new response.

Is there any way to remove fooBar.php from the php stack/memory so I can run it again as though it was never loaded from the first test? I have tried pulling the second test function into its own test class but when I run the testsuite as a whole, I get the same exact error.

2

There are 2 best solutions below

0
On BEST ANSWER

So I figured out a way to do what I was looking for. Long story short, I use CURL to hit the ajax file. This allows me to hit the file multiple times within my test without causing any re-declaration issues. Below is an example of my solution for the fooBarTest.php file.

class fooBarTest extends \PHPUnit\Framework\TestCase
{   

   public function testFooBarSuccess(){
       $postData = array('bar'=>"fooBar");

       $ch = curl_init();
       curl_setopt($ch, CURLOPT_URL, $url);
       curl_setopt($ch, CURLOPT_POST, true);
       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
       curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); 

       $response = curl_exec($ch);      
       curl_close($ch);

       $this->assertTrue((strpos($response, 'success') !== false) && (strpos($response, 'true') !== false));

   }        
   public function testFooBarFailure(){
       $postData = array('bar'=>"notFooBar");

       $ch = curl_init();
       curl_setopt($ch, CURLOPT_URL, $url);
       curl_setopt($ch, CURLOPT_POST, true);
       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
       curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); 

       $response = curl_exec($ch);      
       curl_close($ch);

       $this->assertTrue((strpos($response, 'success') !== false) && (strpos($response, 'false') !== false));

    }
}
1
On

PHP has built-in function to checking that specific function is defined, it's called function_exists. Example:

if (false === function_exists('randomFunctionName')) {
    function randomFunctionName()
    {
        echo "randomFunctionName";
    }
}

Thanks to this, you can include/require file many times but function will be loaded once.

Second way is just import your fooBar.php once using require_once instead of require (Difference between require, include and require_once?).