17

I'm trying to configure a Mock object in PHPunit to return values for different properties (that are accessed using the __get function)

Example:

class OriginalObject {
 public function __get($name){
switch($name)
 case "ParameterA":
  return "ValueA";
 case "ParameterB":
  return "ValueB";
 }
}

I'm trying to mock this using:

$mockObject = $this->getMock("OrigionalObject");

$mockObject    ->expects($this->once())
    ->method('__get')
    ->with($this->equalTo('ParameterA'))
    ->will($this->returnValue("ValueA"));

$mockObject    ->expects($this->once())
    ->method('__get')
    ->with($this->equalTo('ParameterB'))
    ->will($this->returnValue("ValueB"));

but this fails horribly :-(

j0k
  • 22,600
  • 28
  • 79
  • 90
Tim
  • 173
  • 1
  • 1
  • 6
  • 1
    Are the typos ("Origional" instead of "Original", missing closing quotes at ValueA and ValueB) in the mock code part of your actual code, or transcription errors? – Phil Jul 29 '10 at 12:59
  • 1
    LOL thanks Phil (for pointing out my dyslexia) The typos (amended now) are just in the example code - clearly this isn't the actual code being executed – Tim Jul 30 '10 at 05:56

2 Answers2

9

I haven't tried mocking __get yet, but maybe this will work:

// getMock() is deprecated
// $mockObject = $this->getMock("OrigionalObject");
$mockObject = $this->createMock("OrigionalObject");

$mockObject->expects($this->at(0))
    ->method('__get')
    ->with($this->equalTo('ParameterA'))
    ->will($this->returnValue('ValueA'));

$mockObject->expects($this->at(1))
    ->method('__get')
    ->with($this->equalTo('ParameterB'))
    ->will($this->returnValue('ValueB'));

I've already used $this->at() in a test and it works (but isn't an optimal solution). I got it from this tread:

How can I get PHPUnit MockObjects to return different values based on a parameter?

Community
  • 1
  • 1
koen
  • 13,349
  • 10
  • 46
  • 51
  • hey koen $this->at() works for me - Thank you ;-) Why don't you think that this is an optimal solution? – Tim Jul 30 '10 at 05:58
  • 1
    It's not really scalable and the test is difficult to read. A callback may be easier to read if you give it a good name. But in the first place I would look at trying to refactor the __get. – koen Jul 30 '10 at 06:41
  • also, you are testing state (which some regard as bad practice) and even more, private state (which many regard as a bad practice). Of course there are smart folks who don't see a problem in that and you may be one of them. – koen Jul 30 '10 at 06:44
4

This should work:

class Test extends \PHPUnit_Framework_TestCase {
...
    function testSomething() {
         $mockObject = $this->getMock("OrigionalObject");

         $mockObject
              ->expects( $this->any() )
              ->method('__get')
              ->will( $this->returnCallback('myMockGetter'));
         ...
     }
...
}

function myMockGetter( $classPropertyName ) {
    switch( $classPropertyName ) {
        case 'ParameterA':
            return 'ValueA';

        case 'ParameterB':
            return 'ValueB';
    }
}
... ... 
Community
  • 1
  • 1
Johntron
  • 2,443
  • 2
  • 24
  • 26
  • I think my solution is more optimal than koen, but he makes some important points in his comments. I think one possible solution would be to create a test class, and not use a mock object. This is often used for things like HTTP adapters. – Johntron Sep 02 '11 at 01:56