Reputation: 29912
I would like to make some unittest for my application. As is my first time managing with PHPUnit (and unittest more in general) I would like to have an advice.
First, let's say that I have this class
class LodgingManager
{
private $session;
private $entity_manager;
public function __construct(Session $session, EntityManager $em)
{
$this->session = $session;
$this->entity_manager = $em;
}
public function loadLodgingList()
{
//If I've already fetched lodgings from db, use the session one.
//Everytime a lodging is added, session is refreshed
$lodging_list = $this->session->get('lodging_list');
if (!$lodging_list) {
$lodging_repo = $this->entity_manager->getRepository('KoobiBookingEngineBundle:Lodging');
$lodging_list = $lodging_repo->getAllForList();
$this->session->set('lodging_list', $lodging_list);
}
return $lodging_list;
}
[...]
}
This is a simple and silly method but, starting from here to me seems quite useful as code isn't to much complex to follow. As everyone can see I use a custom DQL method that helps me to retrieve some entities and place them into session.
I've created a test database with some dummy data and I would to test them.
As far as i know Doctrine's EntityManager has a protected __construct()
method. This means that you can't use a "real" EntityManager but you need to use a mock one. Same consideration could be done for Repository and so on.
So the code I've producted is the following
class LodgingManagerTest extends \PHPUnit_Framework_TestCase
{
const LODGING_CLASS = 'KoobiBookingEngineBundle:Lodging';
/** @var LodgingManager */
protected $lodging_manager;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $em;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $repository;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $session;
public function setUp()
{
$lodging_array_collection = new ArrayCollection();
$lodging = $this->getMock('Koobi\BookingEngineBundle\Entity\Lodging');
$lodging_array_collection->add($lodging);
$repository = $this->getMockBuilder('Koobi\BookingEngineBundle\Repository\LodgingRepository')
->disableOriginalconstructor()
->getMock();
$repository->expects($this->once())
->method('getAllForList')
->will($this->returnValue($lodging_array_collection));
$this->repository = $repository;
$em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalconstructor()
->getMock();
$em->expects($this->once())
->method('getRepository')
->with($this->equalTo(static::LODGING_CLASS))
->will($this->returnValue($repository));
$this->em = $em;
$this->session = new Session(new MockArraySessionStorage());
$this->lodging_manager = $this->createLodgingManager($this->session, $this->em);
}
public function testLoadLodgingList()
{
$lodging_list = $this->lodging_manager->loadLodgingList();
$this->assertCount(1, $lodging_list);
}
}
Every object of test is a mocked one (except for Lodging that is a "real" one). But to me this test is pretty useless as I can't load real entities from database.
I perfectly know that this kind of test is a silly one, but I can easily imagine some other complex one that need real objects.
So, asking to expert users, what's your opinion about? How can I procede to make more relevant and appropriate tests?
Upvotes: 2
Views: 102
Reputation: 39380
IMHO you should do:
Hope this help
Upvotes: 1
Reputation: 14520
you should refactor you code to separate 'simple, stupid' dao from everything else (session management and business logic). then divide your tests into 2 or 3 groups.
unit tests: testing components in isolation from environment (also from database). in this tests you mock your database (entityManager, repositories, however it's called in your technology) and you check if those mocks are being called as expected
database tests: you use your real entityManager, repositories and mysql/oracle/whatever to test if your sql/orm code is working correctly. you are testing only your database code without any business logic or session management
end-to-end tests. you start whole application and simulate users clicking web interface
Upvotes: 2