I'm new to testing and I am trying to create a unit test that covers the first if statement in the NewsCreator create method.
This question has two parts.
First: How should I be instantiating NewsCreator to handle the mocked validator and repository?
Second: What would the correct way to test this path be?
Here is my controller method that calls the class that needs testing:
public function store()
{
$creator = new NewsCreator($this);
return $creator->create(Input::all());
}
Here is the class that I wish to test, NewsCreator:
<?php namespace WHS\Portal\News;
class NewsCreator {
protected $listener;
protected $repository;
protected $validator;
protected $errors;
public function __construct($listener, NewsRepositoryInterface $repository, NewsValidator $validator)
{
$this->listener = $listener;
$this->repository = $repository;
$this->validator = $validator;
$this->errors = [];
}
public function create($data)
{
if($this->validator->fails($data))
{
return $this->listener->newsCreationFails($this->validator->messages());
}
if($this->repository->create($data))
{
return $this->listener->newsCreationSucceeds();
}
return $this->listener->newsCreationFails($this->errors);
}
}
This is the test I attempted to write, but it fails
with exception:
2) WHS\Portal\Tests\News\NewsCreatorTest::test_failed_validation Mockery\Exception\InvalidCountException: Method fails("foo") from Mockery_1_WHS_Portal_News_NewsValidator should be called exactly 1 times but called 0 times.
<?php namespace WHS\Portal\Tests\News;
use TestCase;
use Mockery as m;
class NewsCreatorTest extends TestCase {
public function tearDown()
{
m::close();
}
public function test_failed_validation()
{
$newsRepo = m::mock('\WHS\Portal\News\DbNewsRepository["create"]');
$newsValidator = m::mock('\WHS\Portal\News\NewsValidator["fails"]');
$listener = new NewsListenerStub();
$listener = m::mock($listener)->makePartial();
$newsValidator->shouldReceive('fails')->with('foo')->once()->andReturn(true);
$listener->shouldReceive('newsCreationFails')->once()->with('foo')->andReturn();
$newsCreator = new \WHS\Portal\News\NewsCreator($listener,$newsRepo,$newsValidator);
$newsCreator->create([]);
}
}
Updated test:
use TestCase;
use Mockery as m;
class NewsCreatorTest extends TestCase {
public function tearDown()
{
m::close();
}
public function test_failed_validation()
{
$newsRepo = m::mock('\WHS\Portal\News\DbNewsRepository["create"]');
$newsValidator = m::mock('\WHS\Portal\News\NewsValidator["fails"]');
$listener = m::mock('\WHS\Portal\Tests\News\NewsListenerStub["newsCreationFails"]');
$newsValidator->shouldReceive('fails')->with([])->once()->andReturn(true);
$newsValidator->shouldReceive('messages')->once();
$listener->shouldReceive('newsCreationFails')->once()->with('foo')->andReturn('foo-bar');
$newsCreator = new \WHS\Portal\News\NewsCreator($listener,$newsRepo,$newsValidator);
$result = $newsCreator->create([]);
$this->assertEquals('foo-bar', $result);
}
}
The stub class:
class NewsListenerStub
{
public function newsCreationFails($data)
{
return $data;
}
}
Please help.
Thanks.