Adding better constructor support to simpletest

I am no fan of PHPUnit. I find it very cumbersome to use, and bloated. But it has one big advantage over simpletest: It does not destroy your constructors when you mock objects.

So, I set out to update the simpletest code to remove that problem. This is accomplished by replacing the createSubclassCode() and extendClassCode() methods of the MockGenerator class in mock_objects.php.

class MockGenerator
{
    ...

    protected function constructorParameterList() {
        if (! method_exists($this->class, '__construct')) return null;

        $reflection = new ReflectionClass($this->class);
        $parameters = $reflection->getMethod('__construct')->getParameters();

        if (! $parameters) return null;

        foreach ($parameters as $parameter)
        {
            $p = '$' . $parameter->name;
            $arguments[] = $p;

            if ($class = $parameter->getClass()) $p = $class->name . ' ' . $p;
            $signature[] = $p;
        }

        return [implode(', ', $signature), implode(', ', $arguments)];
    }

    protected function createSubclassCode($methods) {

        $merged_methods = array_merge($methods, $this->reflection->getMethods());

        $code  = "class " . $this->mock_class . " extends " . $this->class . " {\n";
        $code .= "    public \$mock;\n";
        $code .= $this->addMethodList($merged_methods);
        $code .= "\n";

        if ($parameters = $this->constructorParameterList())
        {
            list($signature, $arguments) = $parameters;

            $code .= "    function __construct(" . $signature . ") {\n";
            $code .= "        parent::__construct(" . $arguments . ");\n";
            $code .= "        \$this->mock = new " . $this->mock_base . "();\n";
            $code .= "        \$this->mock->disableExpectationNameChecks();\n";
            $code .= "    }\n";
        }
        else
        {
            $code .= "    function " . $this->mock_class . "() {\n";
            $code .= "        \$this->mock = new " . $this->mock_base . "();\n";
            $code .= "        \$this->mock->disableExpectationNameChecks();\n";
            $code .= "    }\n";
        }

        $code .= $this->chainMockReturns();
        $code .= $this->chainMockExpectations();
        $code .= $this->chainThrowMethods();
        $code .= $this->overrideMethods($this->reflection->getMethods());
        $code .= $this->createNewMethodCode($methods);
        $code .= "}\n";

        return $code;
    }

    protected function extendClassCode($methods) {
        $code  = "class " . $this->mock_class . " extends " . $this->class . " {\n";
        $code .= "    protected \$mock;\n";
        $code .= $this->addMethodList($methods);
        $code .= "\n";

        if ($parameters = $this->constructorParameterList($methods))
        {
            list($signature, $arguments) = $parameters;

            $code .= "    function __construct(" . $signature . ") {\n";
            $code .= "        parent::__construct(" . $arguments . ");\n";
            $code .= "        \$this->mock = new " . $this->mock_base . "();\n";
            $code .= "        \$this->mock->disableExpectationNameChecks();\n";
            $code .= "    }\n";
        }
        else
        {
            $code .= "    function " . $this->mock_class . "() {\n";
            $code .= "        \$this->mock = new " . $this->mock_base . "();\n";
            $code .= "        \$this->mock->disableExpectationNameChecks();\n";
            $code .= "    }\n";
        }
        $code .= $this->chainMockReturns();
        $code .= $this->chainMockExpectations();
        $code .= $this->chainThrowMethods();
        $code .= $this->overrideMethods($methods);
        $code .= "}\n";

        return $code;
    }
    ...
}