samedi 20 décembre 2014

Laravel partial mocks not working with repository pattern

Been going in circles for a while, and I hope somebody can get me going again...


I'm writing phpunit unit tests for a Laravel 4.2 controller function but get an error telling me that a function doesn't exist on my mock object.


Here's the controller:



use My\Storage\Cond\CondInterface as Cond;

class CondRuleController extends \BaseController {

protected $rule;

public function __construct(Cond $rule)
{
$this->rule = $rule;
}

public function store()
{
// Limit input input
$post = Input::only('A','B','C');

// Calculate and add another value
$post['D'] = $this->rule->nextOrder($post['A']);

// Try to create the rule or throw error
$this->rule = $this->rule->create($post);
if($this->rule->errors) throw new Exception('nope!');

return View::make('success_view');
}


And the interface:



namespace My\Storage\Cond;

interface CondInterface {

public function nextOrder($value);
public function create($data);
...
}


And the Eloquent repository (bound to interface in a Service Provider not shown here):



namespace My\Storage\Cond;

use My\Storage\Cond\CondInterface;
use Cond;

class CondEloquentRepository implements CondInterface {

protected $rule;

public function __construct(Cond $rule)
{
$this->rule = $rule;
}

public function nextOrder($value)
{
$max = $this->rule->whereValue($value)->max('order');
return (empty($max)) ? 1 : $max + 1;
}

// Use Eloquent create() method
public function create($post)
{
return $this->rule->create($post);
}
...
}


Cond is a pretty standard Eloquent model.


And my test:



class CondRuleControllerTest extends TestCase {

public function setUp()
{
parent::setUp();
$this->mock = Mockery::mock("My\Storage\Cond\CondInterface")->makePartial();
$this->controller = new CondRuleController($this->mock);

// Set up passing defaults
$this->input = array('A' => 'red', 'B' => 'blue','C' => 'green');
Input::replace($this->input);

// Extended results following nextOrder
$this->create_data = array('A' => 'red', 'B' => 'blue','C' => 'green', 'D' => 1);
}
public function tearDown()
{
Mockery::close();
}

public function testStoreOK()
{
$this->mock->shouldReceive('nextOrder')
->once()
->with('red')
->andReturn(1);

$this->mock->shouldReceive('create')
->once()
->with($this->create_data)
->andReturn($this->mock);

View::shouldReceive('make')->once()->with('success_view');

$this->controller->store();
}


When I run this, then I get the following error:



1) CondRuleControllerTest::testStoreOK
BadMethodCallException: Method Mockery_0_My_Storage_Cond_CondInterface::create() does not exist on this mock object


I'm confused why create() doesn't appear to be mocked correctly, but nextOrder() does. Perhaps it is clashing with Eloquent's create()?


On a seperate (unrelated) note, I found that removing the with() statement in the second shouldReceive() makes the test pass, but with zero assertions.


Any suggestions gratefully received!


Aucun commentaire:

Enregistrer un commentaire