3

I'm trying to test a private method in an abstract class.

I've got three abstract classes:

abstract class AbstractClass1 extends AbstractClass2
{
   private function _privateFunction()
    {
        //method's body
    }
}

abstract class AbstractClass2 extends AbstractClass3
{
    public function __construct($param)
    {
        parent::__construct($param)
    }
}

abstract class AbstractClass3
{
    public function __construct($param = array()) 
    {
        //something
    }
}

The test class:

class AbstractClass1Test extends PHPUnit_Framework_TestCase
{
    public function test_privateFunction()
    {
        $stub = $this->getMockForAbstractClass("AbstractClass1");
        $class = new ReflectionClass($stub);
        $method = $class->getMethod("_privateFunction");
        $method->setAccessible(true);

        //some assertings with $method->invoke($stub)
    }
}

The test failed, because of the error:

Missing argument 1 for AbstractClass2::__construct(), called in /usr/share/php/PHPUnit/Framework/MockObject/Generator.php on line 190 and defined

AbstractClass2.php

public function __construct($param)

AbstractClass1.php

$classMock = $this->getMockForAbstractClass("AbstractClass1");

Generator.php:190

if ($callOriginalConstructor &&
    !interface_exists($originalClassName, $callAutoload)) {
    if (count($arguments) == 0) {
        <strong>$mockObject = new $mock['mockClassName'];</strong>
    } else {
        $mockClass  = new ReflectionClass($mock['mockClassName']);
        $mockObject = $mockClass->newInstanceArgs($arguments);
    }
} else ...

What do I wrong? Or how can I test my private function in this situation?

faramka
  • 2,164
  • 1
  • 18
  • 21
  • Where are you passing arguments to the constructor? – Nathan Loding Oct 18 '11 at 12:20
  • 1
    possible duplicate of [PhpUnit private method testing](http://stackoverflow.com/questions/5937845/phpunit-private-method-testing) – Gordon Oct 18 '11 at 12:30
  • 1
    [Sebastian Bergmann's Blog: Testing your privates](http://sebastian-bergmann.de/archives/881-Testing-Your-Privates.html) – Gordon Oct 18 '11 at 12:30
  • @Nathan Loding: I set the parameter of contructor of abstract class AbstractClass2 as optional, but now I've got an exception associated with the DB adapter. So this is not a problem with testing as I thought. – faramka Oct 18 '11 at 13:28
  • 1
    @Gordon: thanks; http://stackoverflow.com/questions/5010300/best-practices-to-test-protected-methods-with-phpunit-on-abstract-classes there is also something interesting posted by David Harkness – faramka Oct 18 '11 at 13:32

2 Answers2

5

You need to pass an argument to AbstractClass1's constructor. Pass constructor arguments in an array as the second argument to getMockForAbstractClass().

$stub = $this->getMockForAbstractClass("AbstractClass1", array('param'));
David Harkness
  • 35,992
  • 10
  • 112
  • 134
0

Seeing as you overrode the original constructor,

public function __construct($param = array())  //Allow null $param as it would default to array();

With a new one:

public function __construct($param) //Does not allow null $param.

You will require to define the $param when you initialize the object. That's probably your problem.

Objects in PHP are not like JavaScript, they cannot be called like associative arrays. Your object initialization should look like:

$mockObject = new ClassExtendingAbstractClass1Or2('parameter');

The new keyword cannot be used in front of a variable.

Madara's Ghost
  • 172,118
  • 50
  • 264
  • 308