I'm trying to create unit test with phpunit for Zend, using Doctrine ORM. When I try to create a test class extending Zend_Test_PHPUnit_DatabaseTestCase, I get a message when executing PHPUnit: "There is no open connection"
Here is the full source:
<?php
class AclTest extends Zend_Test_PHPUnit_DatabaseTestCase
{
private $_userAdmin;
public function setUp()
{
$this->bootstrap = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
$this->_userAdmin = Model_UserTable::getInstance()->findOneByUsername('admin');
parent::setUp();
}
protected function getConnection()
{
$pdo = new PDO('mysql:host=localhost;dbname=mydbname', 'root', 'pwd');
return $this->createDefaultDBConnection($pdo, 'testdb');
}
protected function getDataSet()
{
return null;
}
public function testHasProfilPermission()
{
//execute some tests
}
}
What do you think ?
Thanks
Try this, please:
class AclTest extends Zend_Test_PHPUnit_DatabaseTestCase
{
private $_userAdmin;
/** #var PDO **/
protected $pdo;
public function __construct()
{
$this->pdo = new PDO('mysql:host=localhost;dbname=mydbname', 'root', 'pwd');
}
public function setUp()
{
$this->bootstrap = new Zend_Application(APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini');
$this->_userAdmin = Model_UserTable::getInstance()->findOneByUsername('admin');
parent::setUp();
}
protected function getConnection()
{
return $this->createDefaultDBConnection($this->pdo, 'testdb');
}
}
Related
I'm new to ZF2. After few days of trying to figure out how all this stuff should work I was unable to figure out how should I call TableGateway Model from Service.
So I have Controller:
class SubscriberController extends AbstractActionController
{
/**
* #var \Subscriber\Service\SubscriberServiceInterface
*/
private $subscriberService;
/**
* #param $subscriberService
*/
public function __construct(SubscriberServiceInterface $subscriberService)
{
$this->subscriberService = $subscriberService;
}
Factroy for this Controller:
class SubscriberControllerFactory implements FactoryInterface
{
/**
* Returns ArchiveController instance.
*
* #param ServiceLocatorInterface $serviceLocator
* #return SubscriberController
* #override
**/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$sm = $serviceLocator->getServiceLocator();
return new SubscriberController(
$sm->get('Subscriber\Service\SubscriberServiceInterface')
);
}
Some SubscriberTable:
class SubscriberTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
And Service in which I want to get SubscriberTable instance and make some logic. But I can't figure out how should I call this instance in SubscriberService and set the DbAdapter for SubscriberTable
First implement servicelocator interface and define get and set locator functions to your service like this.
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class Yourservice implements ServiceLocatorAwareInterface{
function test(){
$this->getSubscriberTable->fetchAll(); // call to subscriber table functions
}
/**
* #table gateway Call
**/
public function getSubscriberTable()
{
if (!$this->SubscriberTable) {
$sm = $this->getServiceLocator();
$this->SubscriberTable = $sm->get('Application\Model\SubscriberTable');
}
return $this->SubscriberTable;
}
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
}
Hope it will help you.
TLDR: I am new to unit tests and I have few questions:
Are my transformer tests well written?
Is there a way to decoupled my transformer tests from the database?
How to test my form with the transformer using the database?
Should I decouple my form from my transformer?
I don't know if my classes are too coupled, if my design is flawed or if my understanding of the unit tests is bad.
Here is some background.
I have a form object with different widgets. One of them is used within a model transformer.
This model transformer uses a connection to the database to retrieve the proper object.
Here is my code:
class BookToStringTransformer implements DataTransformerInterface {
private $om;
public function __construct(ObjectManager $om) {
$this->om = $om;
}
public function transform($book) {
if (!$book instanceof Book) {
return "";
}
return $book->getName();
}
public function reverseTransform($string) {
if (!is_string($string) || !$string) {
return null;
}
$book = $this->om
->getRepository('MyBundle:Book')
->findOneBy(array('name' => $string))
;
if (null === $book) {
throw new TransformationFailedException(sprintf(
'The book "%s" does not exist!', $string
));
}
return $book;
}
}
class ItemType extends AbstractType {
private $om;
public function __construct(ObjectManager $om) {
$this->om = $om;
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$bookTransformer = new BookToStringTransformer($this->om);
$builder->add($builder->create('book', 'text', array(
'required' => false,
))->addModelTransformer($bookTransformer));
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'MyBundle\Entity\Item',
));
}
public function getName() {
return 'mybundle_item';
}
}
I wrote unit tests for the transformer using the KernelTestCase
class BookToStringTransformerTest extends KernelTestCase {
private $name = 'existing name';
private $em;
public function setUp() {
static::$kernel = static::createKernel();
static::$kernel->boot();
$this->em = static::$kernel->getContainer()
->get('doctrine')
->getManager();
}
public function testReverseTransform_whenNameExists_returnsBookObject() {
$transformer = new BookToStringTransformer($this->em);
$book = $transformer->reverseTransform($this->name);
$this->assertInstanceOf('MyBundle\Entity\Book', $book, 'Should return a Book object');
$this->assertEquals($this->name, $book->getName(), 'Should return a Book object with the selected name');
}
/**
* #expectedException Symfony\Component\Form\Exception\TransformationFailedException
*/
public function testReverseTransform_whenNameDoesNotExist_throwsException() {
$transformer = new BookToStringTransformer($this->em);
$transformer->reverseTransform('unknown name');
}
/**
* #param mixed $invalid_parameter
* #dataProvider provideInvalidParameter
*/
public function testReverseTransform_whenParameterIsInvalid_returnsNull($invalid_parameter) {
$om = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')->getMock();
$transformer = new BookToStringTransformer($om);
$this->assertNull($transformer->reverseTransform($invalid_parameter), 'Should return a NULL value');
}
/**
* #return array
*/
public function provideInvalidParameter() {
return [
[null],
[false],
[true],
[''],
[[]],
[new \stdClass()],
];
}
public function testTransform_whenParameterIsBookObject_returnsName() {
$book = $this->em->getRepository('MyBundle:Book')
->findOneBy(array('name' => $this->name));
$om = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')->getMock();
$transformer = new BookToStringTransformer($om);
$this->assertEquals($this->name, $transformer->transform($book), 'Should return a string containing the name');
}
/**
* #param mixed $not_book
* #dataProvider provideInvalidBookObject
*/
public function testTransform_whenParameterIsNotBookObject_returnsEmptyString($not_book) {
$om = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')->getMock();
$transformer = new BookToStringTransformer($om);
$this->assertEquals("", $transformer->transform($not_book), 'Should return an empty string to be chained');
}
/**
* #return array
*/
public function provideInvalidBookObject() {
return [
[null],
[123],
['123'],
[[]],
[true],
[new \stdClass()],
];
}
}
As I am new to unit tests, I don't even know if it is the proper way to test that transformer.
I start writing tests for the form object. I am using the TypeTestCase but there is no simple way to get the connection to the database and I can't use the KernelTestCase.
class ItemTypeTest extends TypeTestCase {
/**
* #expectedException \PHPUnit_Framework_Error
*/
public function test_whenCreatedWithNoParameters_raiseException() {
new ItemType();
}
/**
* #expectedException \PHPUnit_Framework_Error
*/
public function test_whenCreatedWithBadParameters_raiseException() {
new ItemType(123);
}
public function test_whenCreatedWithGoodParameters_createsFormObject() {
$om = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')->getMock();
$type = new ItemType($om);
$form = $this->factory->create($type);
$this->assertInstanceOf('Symfony\Component\Form\Form', $form);
}
public function test_whenSubmittedWithGoodData() {
$formData = array(
'name' => 'existing name',
);
$om = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')->getMock();
$type = new ItemType($om);
$form = $this->factory->create($type);
$form->submit($formData);
}
}
The last test fails because the transformer does get access to the database since I am passing a mock to the form. So should I get a real object (meaning classes are too coupled) or should I find an other way.
Thank you
The approach is good, in the last method you must mock the repo object and the repo response. In example try this code:
public function test_whenSubmittedWithGoodData() {
$formData = array(
'name' => 'existing name',
);
$om = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')->getMock();
$repoMock= $this->getMock('Doctrine\ORM\EntityRepository', array(), array(), '', false);
$om
->expects($this->atLeastOnce())
->method('getRepository')
->withAnyParameters()
->will($this->returnValue($repoMock));
$repoMock
->expects($this->atLeastOnce())
->method('findOneBy')
->withAnyParameters()
->will($this->returnValue($mockedBook));
$type = new ItemType($om);
$form = $this->factory->create($type);
$form->submit($formData);
}
I'm going to use SlmQueue (https://github.com/juriansluiman/SlmQueueDoctrine).
How can I get doctrine2 entitymanager inside job class?
I've managed to make this like this:
class DistributeNewsJob extends AbstractJob implements QueueAwareInterface, ServiceLocatorAwareInterface
{
use QueueAwareTrait;
public function execute()
{
// job code
}
private $entityManager;
private function getEntityManager()
{
if (null === $this->entityManager) {
$this->entityManager = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
return $this->entityManager;
}
private $services;
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->services = $serviceLocator->getServiceLocator();
}
public function getServiceLocator()
{
return $this->services;
}
public function dispatch(Request $request, Response $response = null)
{
}
}
We can also do this :
You can use ObjectManagerAwareInterface from doctrine module
use DoctrineModule\Persistence\ObjectManagerAwareInterface;
use DoctrineModule\Persistence\ProvidesObjectManager as ProvidesObjectManagerTrait;
class EmailJob extends AbstractJob implements ObjectManagerAwareInterface
{
use ProvidesObjectManagerTrait;
}
That way you have ObjectManager in your job.
I tried to inject doctrine entity manager in zf2 form in the way that is described here
http://zf2cheatsheet.com/#doctrine (Inject the Entity Manager to Form) but it fails with error _construct() must be an instance of Doctrine\ORM\EntityManager, null given...
Anybody solved this problem ?
There are a few ways on how to do this. The dirty but easier way is to just give the form In your Controller Action The Entity Manager trough a param like so:
/**
* #var Doctrine\ORM\EntityManager
*/
protected $em;
public function getEntityManager()
{
if (null === $this->em) {
$this->em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default');
}
return $this->em;
}
public function setEntityManager(EntityManager $em)
{
$this->em = $em;
}
...
public function yourAction() {
...
$form = new YourForm($this->getEntityManger());
...
}
You then can just call entity Manager methods within your form:
public function __construct($em)
{
...
$repository = $em->getRepository('\Namespace\Entity\Namespace');
...
}
The more complex but nicer way requires you to add the getServiceconfig function within your modules Module.php:
public function getServiceConfig()
{
return array(
'factories' => array(
'YourFormService' => function ($sm) {
$form = new YourForm($sm);
$form->setServiceManager($sm);
return $form;
}
)
);
}
Within your Form you´ll need to implent the ServiceManagerAwareInterface and the setServiceManager setter.
use Zend\Form\Form as BaseForm;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
class CategoryForm extends BaseForm implements ServiceManagerAwareInterface
{
protected $sm;
public function setServiceManager(ServiceManager $sm)
{
$this->sm = $sm;
}
public function __construct($sm)
{
...
$em = $sm->get('Doctrine\ORM\EntityManager');
...
}
You then have to call your Form within your controller differently. The usual$form = new YourForm(); constructor will not work with the factory we created.
$form = $this->getServiceLocator()->get('YourFormService');
I usually use the dirty way to get the Entitymanager but as soon as I need the Service Locator I create a factory personally I dont think its worth it to create a big overhead with the services.
I hope this helped a bit.
i am using zend framework 1.10 with doctrine 2. i wonder if in my (doctrine) model class, isit a good idea to reference a variable set by my application (bootstrap.php, variable stored in Zend_Registry, i think its something like a global variable)
what i want to access is the doctrine entityManager. also i want the id of the logged in user
I am building a project with similar setup (ZF 1.10 + Doctrine2) and I've used dependency injection to deal with this situation, much like takeshin said. Here goes full project repository URL: https://bitbucket.org/phpfour/zf-doctrine2. Below are some code excerpts.
Here's my controller:
<?php
require_once APPLICATION_PATH . "/models/PostManager.php";
class IndexController extends Zend_Controller_Action
{
private $_em;
public function init()
{
$this->_em = $this->getInvokeArg('bootstrap')->getResource('doctrine');
}
public function indexAction()
{
$pm = new PostManager($this->_em);
$this->view->posts = $pm->getPublicPosts();
}
My entity manager (or service class):
<?php
class PostManager
{
protected $_em;
public function __construct(Doctrine\ORM\EntityManager $em)
{
$this->_em = $em;
}
public function getPublicPosts()
{
$query = $this->_em->createQuery('SELECT p FROM Entities\Post p WHERE p.visible = true');
$posts = $query->getResult();
return $posts;
}
Hope this helps!
you should simply use Zend_Auth for the logged-in-userId problem, then could do something like the following in your model
class Model extends BaseModel
{
public function something()
{
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
$loggedInUserId = $auth->getIdentity()->id;
}
}
}
There is nothing wrong with this approach (unless you are referring to singletons). Use dependency injection where possible.
However I'd create a service (or two) for this.
class Modulename_Services_Servicename
{
public function getCurrentUser() { ... }
public function getCurrentUserModel() { ... }
public function isLogged() { ... }
public function authenticate() { ... }
public function getSomeData()
{
$user = $this->getCurrentUser()
$model = new YourModel($user);
$query = ....;
$result = $query->execute();
return $result;
}
public function getSomeMoreData($usermodel) { ... }
}