Bryan M. Bryan M. - 3 months ago 12
PHP Question

PHPUnit: stub methods undefined

I must be missing something. I'm trying to stub methods on a class in PHPUnit, but when I invoke the method on the mock object, it tells me that method is undefined.

Example class to stub:

namespace MyApp;

class MyStubClass
{
public function mrMethod()
{
// doing stuff
}
}


To stub it, I write:

// specifying all getMock() args to disable calling of class __construct()
$stub = $this->getMock('MyStubClass', array(), array(), 'MockMyStubClass', false, false, false);
$stub->expects($this->any())
->method('mrMethod')
->will($this->returnValue('doing stuff'));


But upon invoking the stubbed method, I get an exception:

$stub->mrMethod();
//PHP Fatal error: Call to undefined method MockMyStubClass::mrMethod()


I'm using PHPUnit 3.4.3 with PHP 5.3.0.

Another small thing I noticed was that if specifying a namespace in the
getMock()
method results in a class loading exception because of a double namespace:

$stub = $this->getMock('MyApp\MyStubClass');
// Fatal error: Class 'MyApp\MyApp\MyStubClass' not found


That strikes me as rather odd (and getmock() will not accept a namespace with a leading backslash). The only thing I could think to cause that would may be because this class is
registered with an autoloader?

Any thoughts?

Answer

Answering my own question:

After quite a bit of frustration, I did manage to get things working. I'm not sure precisely what the issue was, but did discover a few things that might help others:

  • Make sure you're running the latest version of PHPUnit (3.4.6 as of this writing)
  • Use the fully-qualified namespace minus the first backslash.

    $this->getMock('MyApp\Widgets\WidgetFactory');
    

Part of my problem was that PHPUnit was creating a stub class WidgetFactory that was not actually stubbing MyApp\Widgets\WidgetFactory. One would expect that an exception would occur if trying to stub a non-existent class, but it doesn't seem to happen with the namespace confusion.

Also, there is a question over here that suggests using the class alias method as follows:

    class_alias('MyApp\Widgets\WidgetFactory', 'WidgetFactory');
    $this->getMock('WidgetFactory');

While this did temporarily solve my problem, I would strongly advise against using it. class_alias() cannot be called twice for the same alias without raising an exception, which causes obvious problem if used in the setup() method, or as part of the stub generation.

Comments