26

Is there any way of testing procedural code? I have been looking at PHPUnit which seems like a great way of creating automated tests. However, it seems to be geared towards object oriented code, are there any alternatives for procedural code?

Or should I convert the website to object oriented before attempting to test the website? This may take a while which is a bit of a problem as I don't have a lot of time to waste.

Thanks,

Daniel.

Daniel West
  • 1,758
  • 2
  • 20
  • 34
  • 1
    Related: http://stackoverflow.com/questions/899390/how-do-i-write-unit-tests-in-php-with-a-procedural-codebase – Sean Walsh Feb 16 '11 at 19:38
  • 2
    PHPUnit uses object-structured interfaces itself for parity with other xUnit incarnations and because that simplified its own implementation. But that doesn't mean it cannot be used for testing procedural code. (Might not be the only/best option however.) – mario Feb 16 '11 at 19:42
  • Yes Mario, I have seen others like SimpleTest however PHPUnit seems to be the most used and I have some experience with JUnit so the learning curve should be fairly minimal! – Daniel West Feb 16 '11 at 20:26

1 Answers1

36

You can test procedural code with PHPUnit. Unit tests are not tied to object-oriented programming. They test units of code. In OO, a unit of code is a method. In procedural PHP, I guess it's a whole script (file).

While OO code is easier to maintain and to test, that doesn't mean procedural PHP cannot be tested.

Per example, you have this script:

simple_add.php

$arg1 = $_GET['arg1'];
$arg2 = $_GET['arg2'];
$return = (int)$arg1 + (int)$arg2;
echo $return;

You could test it like this:

class testSimple_add extends PHPUnit_Framework_TestCase {

    private function _execute(array $params = array()) {
        $_GET = $params;
        ob_start();
        include 'simple_add.php';
        return ob_get_clean();
    }

    public function testSomething() {
        $args = array('arg1'=>30, 'arg2'=>12);
        $this->assertEquals(42, $this->_execute($args)); // passes

        $args = array('arg1'=>-30, 'arg2'=>40);
        $this->assertEquals(10, $this->_execute($args)); // passes

        $args = array('arg1'=>-30);
        $this->assertEquals(10, $this->_execute($args)); // fails
    }

}

For this example, I've declared an _execute method that accepts an array of GET parameters, capture the output and return it, instead of including and capturing over and over. I then compare the output using the regular assertions methods from PHPUnit.

Of course, the third assertion will fail (depends on error_reporting though), because the tested script will give an Undefined index error.

Of course, when testing, you should put error_reporting to E_ALL | E_STRICT.

netcoder
  • 61,842
  • 17
  • 117
  • 139
  • Thanks for the detailed reply! It's Helped me out a lot. I actually have functions that deal with all the business logic so I'm guessing I can include the PHP file with these and and test these in a similar way? – Daniel West Feb 16 '11 at 20:25
  • 2
    @Daniel: Yes. Actually, testing functions is a lot like testing object methods. You send it some input and validate if the output matches what you expect. – netcoder Feb 16 '11 at 20:27
  • Downvoted for the following _opinion_ stated in this answer: "OO code is easier to maintain and to test". That is absolutely not true. – Josh Habdas May 18 '17 at 05:28
  • 1
    This answer doesn't really help to unit test procedural code. Please suggest how we can handle dependencies between functions? One function may be calling several other function inside it. So how can I test that one function in isolation from its dependencies? If code was object oriented I could use mock/stub objects etc to simulate the behavior of various dependencies to generate several possible test cases. – rineez Oct 09 '17 at 07:48
  • how are we supposed to manage script uris and ergo include statements? Surely just hardcoding them into the test method is not the correct way? – tscherg May 11 '18 at 10:42