具有依赖注入的同一类的Mock方法 - PHP

i was wondering on how i can mock a method on the same class that this class have a dependency itself.

Let's say an example:

Class SomeClassA {

  protected $dependency;

  function __construct(Dependency $dependency) {

     $this->dependency = $dependency;

  }


  public function methodToTest() {

         if ( !is_null( $this->methodCalled() ) )

            return $this->methodCalled();

         else

            return "it\'s not ok!"

         // need to test this method mocking the methodCalled()

  }


  public function methodCalled($message) {

        return $message;

  }


}

if this class did not have the dependency i could do something like so:

public function test_methodToTest() {

    $this->getMock('SomeClassA',['methodCalled'])
         ->with('message')
         ->expects($this->once())
         ->will($this->returnValue('message'));

   $someClassA = new SomeClassA();

   $this->assertEquals('message',$someClassA->methodToTest('message'));


}

Edit:

Let's say this example to improve the meaning of my question i just changed a little bit the previous example:

Class SomeClassA {

  protected $dependency;

  function __construct(Dependency $dependency) {

     $this->dependency = $dependency;

  }


  public function methodToTest() {

         if ( $this->methodCalled() ) // i was wondering how mock this method

            return $this->dependency->someDependencyMethod(); // not this

         else

            return "it\'s not ok!"



  }


  public function methodCalled() {

        return true;

  }


}

I just didn't understand how I can mock the method $this->methodClass(). I found hard it because the class SomeClassA have a dependency. And i'm testing a method of that class.

You can do as follows:

class SomeClassATest {
    public function testMethodToTest() {
        $someClassA = $this->getMockBuilder('SomeClassA')
            ->setMethods(array('methodCalled'))
            ->getMock();
        $someClassA->expects($this->once())
            ->method('methodCalled')
            ->will($this->returnValue('your mocked value here'));
        $actual = $someClassA->methodToTest();
        $this->assertEquals('your expectation here', $actual);
    }
}

This will only work if methodCalled is either public or protected, since you can only mock public and protected methods. The way it works up there is you are testing $someClassA, a mock instance of SomeClassA, where only methodCalled is replaced with your test behavior, and everything else stays the same.

You'll be doing this a lot with unit tests:

  • Mock the dependency.
  • Set up expectations on the dependency.
  • Inject the mocked dependency into a real, non-mocked object.

To show a real example, your dependency needs to be actually used (which it isn't in your sample code, I think your code may be broken). So lets change your methodToTest class to this as an example:

public function methodToTest() { return $dependency->returnValue(); }

So now your methodToTest returns a value it gets from dependeency. To test this, lets mock a dependency:

$dep = $this->getMock('Dependency');

Then lets set expectations and what it returns:

$dep->expects($this->once())
     ->method('returnValue')
     ->will($this->returnArgument('hello world'));

Here we are saying that the dependency expects returnValue to be called once and will return the string 'hello world'.

Now lets test the actual class:

$tester = new SomeClassA($dep);

Notice we inject the mock dependency into a real SomeClassA.

$this->assertEquals('hello world',$tester->methodToTest());

This assertion is the only 'visible' one. It makes sure that methodToTest returns the value from the dependency. The test will also make sure that 'returnValue' function on the dependency is called exactly once.