Search code examples
phptestingmockingphpspec

mocking database in derived class


I've got Repository classes which implement a specific interface and also extend a base class for the specific database.

base class:

abstract class CouchDB
{
  protected $db;

  public function __construct(Sag $db)
  {
    $this->db = $db;
  }

  private function call_get($url) {...} //this is a wrapper for $db->get()
}

derived class:

class CouchExpression extends CouchDB implements ExpressionInterface
{
  public function __construct(Sag $db)
  {
    parent::__construct($db);
  }
}

the spec:

class CouchExpressionSpec extends ObjectBehavior
{
  public function let($db)
  {
    $db->beADoubleOf('\Sag');

    $this->beConstructedWith($db);
  }

  public function it_gets_returned_by_its_id()
  {
     $this->db->get('...')->willReturn([]);
  }
}

When running PHPSpec I get: property db not found Is there a way to fix this other than setting the property to public?

After setting it to publicI get: call to a member function willReturn() on a non-object. So I can't run ->willReturn() on $this->db

But why? When doing this in the letmethod of the test it works. But not all tests do need the same data returned...

How do I get this running?


Solution

  • You can declare your double without the explicit call, like this:

    function let(\Sag $db)
    {
        $this->beConstructedWith($db);
    }
    

    Having done this, if you pass a property of the same name to your example, it will be the same instance of the double:

    function it_gets_returned_by_its_id($db)
    {
        $db->get('...')->willReturn([]);
    }
    

    Also, by convention let and example methods don't use the public keyword, they'll be public anyway and it reduces noise around your examples.