How can I test a Lib in CakePHP2.4? - unit-testing

I moved some code from a model to a Lib in my app, because it can be used from 2 models and is not database related. It is an uploadhandler, which is used from my two models. It is placed at /app/Lib/UploadHandler.php
That works. Hurray...
But: How can I write Unit Tests for my Lib? It is a lib not 3rd party classes which would belong into the vendor folder. I created a TestClass in an new folder "Lib" in
/app/Test/Case/Lib/UploadHandlerTest.php
What I do so far is:
App::uses('UploadHandler', 'Lib');
/**
* UploadHandler Test Case
*
*/
class UploadHandlerTestCase extends CakeTestCase
{
/**
* Fixtures
*
* #var array
*/
public $fixtures = array();
/**
* setUp method
*
* #return void
*/
public function setUp() {
parent::setUp();
$this->UploadHandler = ClassRegistry::init('UploadHandler');
}
/**
* tearDown method
*
* #return void
*/
public function tearDown() {
unset($this->UploadHandler);
parent::tearDown();
}
public function testHandleFileUpload() {....
which gives me errors like:
MissingTableException
Table sang_upload_handlers for model UploadHandler was not found in datasource test.
Test case: UploadHandlerTestCase(testHandleFileUpload)
But - hey I don't need the database! All my methods run just with the data I give the public methods.
What would be the proper initialization of my test class?
Thank you for any help!
Calamity Jane

So in case anybody except me is interested in it I found a way to make it work like I want.
First the folder structure:
Class location:
app/Lib/MyLib.php
Test class location:
app/Test/Case/Lib/MyLibTest.php
By this you can see the Test for your library in the CakePHP browser webinterface.
Second: How to prevent the error about dabase tables.
The answer is quite simple: Just let your testclass extend not the CakeTestCase, but use the original PHPUnit_Framework_TestCase and you will have no trouble with missing tables.
Duh....
Example:
require_once DS.'var'.DS.'www'.DS.'myproject'.DS.APP_DIR.DS.'/Lib/UploadHandler.php';
/**
* UploadHandler Test Case
*
*/
class UploadHandlerTestCase extends PHPUnit_Framework_TestCase
{....
I was happy to help myself ;) I guess a lot of sleep during the change of the year did the trick ;)
Calamity Jane

Related

Symfony 5 - One entity, one Repository and two Databases

I have a problem querying my database via Symfony Repository.
If I don't specify a repository
/**
* ProductsText
*
* #ORM\Table(name="products_text")
* #ORM\Entity
*/
i can select one of my databases by using Doctrine like this:
->getRepository(ProductsText::class, "db1").
But if i declare the repository:
/**
* ProductsText
*
* #ORM\Table(name="products_text")
* #ORM\Entity(repositoryClass="App\Repository\Product\ProductsTextRepository")
*/
It only selects the database from which I pulled the entity from.
I can't use two different entities because the user selects the "database" when logging in. Unfortunately, I can't merge the two databases yet either, as they are not multi-tenant.
My guess is that I can solve the problem by keeping the registry from the repository in general. My previous attempts unfortunately ended up with the front end no longer loading.
Works, but only for one database:
class ProductsTextRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ProductsText::class);
}
Did not works:
class TbProductsTextRepository
{
/**
* #var EntityRepository
*/
private $repository;
public function __construct(EntityManagerInterface $entityManager)
{
$this->repository = $entityManager->getRepository(TbProductsText::class);
}
Unfortunately, I don't understand the mechanics of how the repositorys are regestrated.
I use:
Symfony 5.2
Doctrine 2.2
Doctrine ORM 2.8
Doctrine Migrations Bundle 3.0
I solved the problem by not "registering" the repository.
By using EntityRepository and without a construct, I can use the repository for both databases.
use Doctrine\ORM\EntityRepository;
class TbProductsTextRepository extends EntityRepository
{

proper way to test a service in Symfony 4, with database access

What would be the proper way to test a service in Symfony 4, which also accesses the database?
I am new in Symfony4 (before I developed for Symfony2) and I want to write my first test for a Service.
This service is writing via Entities / Doctrine / ORM in the database and each of my methods, I want to test is triggering a database save.
In Symfony 2 this was the case when I used rather KernelTestCase instead of the PHPUnit_Framework_TestCase because mocking the EntityManager was a pain in the ass and often I also wanted to check the result in the test db.
All examples for Symfony 4 only mention the KernelTestCase for testing Commands.
My class:
class UserPropertyService implements UserPropertyServiceInterface
{
public function __construct(EntityManager $em, LoggerInterface $logger)
{
....
}
....
}
My attempt at a Test:
class UserPropertyServiceTest extends KernelTestCase
{
/** #var UserPropertyService */
private $userPropertyService;
public function setUp()
{
self::bootKernel();
$client = static::createClient();
$container = $client->getContainer();
$this->userPropertyService = self::$container->get('app.user_management.user_property_service');
}
results in:
Cannot autowire service "App\Service\UserManagement\UserPropertyService": argument
"$em" of method "__construct()" references class "Doctrine\ORM\EntityManager"
but no such service exists.
Try changing the type-hint to one of its parents: interface "Doctrine\ORM\EntityManagerInterface",
or interface "Doctrine\Common\Persistence\ObjectManager".
What is the proper approach here? Which test class should I use?
This is how look like a service test (do not get your Container through the client, those containers are different)
By the way, you can't use static::createClient(); if you extend from KernelTestCase (misunderstanding with controller test and the WebTestCase class ?)
<?php
namespace App\Tests\Service;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class UserPropertyServiceTest extends KernelTestCase
{
/** #var UserPropertyService */
private $myService;
public function setUp() {
self::bootKernel();
$this->myService = self::$kernel->getContainer()->get('app.user_management.user_property_service');
}
}

Understanding the logic flow of mock tests

In an effort to learn the logic flow of mock tests I've unsuccessfully reproduced a test from a Symfony article using code from my application.
Background: Volunteer entity extends the abstract class Person, which extends the FOSUserBundle model User. Person includes methods for firstName, lastName, and name. Name returns lastName, firstName. The test that appears below returns this:
--- Expected
+++ Actual
## ##
-'Borko, Benny'
+', '
How should this test be modified? Better yet, how do you tell when it's your test design and not the system under test that's failing?
Edit: see result of applying proposed solution below
Edit #2:
Not sure if this is relevant: Volunteer and two other entities are mapped via Inheritance Mapping to the Person entity (see PUGXMultiUserBundle).
The test:
use Truckee\MatchingBundle\Entity\Volunteer;
class MockVolunteerTest extends \PHPUnit_Framework_TestCase
{
public function testFullName()
{
// First, mock the object to be used in the test
$volunteer = $this->getMock('\Truckee\MatchingBundle\Entity\Volunteer');
$volunteer->expects($this->once())
->method('getFirstName')
->will($this->returnValue('Benny'));
$volunteer->expects($this->once())
->method('getLastName')
->will($this->returnValue('Borko'));
// Now, mock the repository so it returns the mock of the volunteer
$volunteerRepository = $this->getMockBuilder('\Doctrine\ORM\EntityRepository')
->disableOriginalConstructor()
->getMock();
$volunteerRepository->expects($this->once())
->method('find')
->will($this->returnValue($volunteer));
// Last, mock the EntityManager to return the mock of the repository
$em = $this->getMockBuilder('\Doctrine\Common\Persistence\ObjectManager')
->disableOriginalConstructor()
->getMock();
$em->expects($this->once())
->method('getRepository')
->will($this->returnValue($volunteerRepository));
$user = new Volunteer();
$this->assertEquals('Borko, Benny', $user->getName());
}
}
Proposed solution:
class VolunteerTest extends \PHPUnit_Framework_TestCase
{
/**
* #var Volunteer
*/
protected $object;
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
$this->object = new Volunteer();
}
public function testGetterAndSetter() {
$this->assertNull($this->object->setFirstName("Benny"));
$this->assertEquals("Benny", $this->object->getFirstName());
$this->assertNull($this->object->setLastName("Borko"));
$this->assertEquals("Borko", $this->object->getLastName());
$this->assertEquals('Borko, Benny', $this->object->getName());
}
}
Test results:
Failed asserting that Truckee\MatchingBundle\Entity\Volunteer Object
&0000000067c9c33f00000000680c6030 (
'id' => null ...
'credentialsExpireAt' => null ) is null.
The main goal of mocks is to test repositories or services. There is a easier way to test your entity:
class VolunteerTest extends \PHPUnit_Framework_TestCase {
/**
* #var Volunteer
*/
protected $object;
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp()
{
$this->object = new Volunteer();
}
public function testGetterAndSetter() {
$this->assertNull($this->object->setFirstName("Benny"));
$this->assertEquals("Benny", $this->object->getFirstName());
$this->assertNull($this->object->setLastName("Borko"));
$this->assertEquals("Borko", $this->object->getLastName());
}
}
The answer here is that the test is an inappropriate use of mock testing. After reading the article "An Introduction to Mock Object Testing" it became clear that the technique is to mock the dependencies of the system (object) under test, not the object itself. In the test I attempted, the Volunteer entity was the SUT so it should not have been mocked.

How to get a Respository from an Entity?

I have an Entity called Game with a related Repository called GameRepository:
/**
* #ORM\Entity(repositoryClass="...\GameRepository")
* #ORM\HasLifecycleCallbacks()
*/
class Game {
/**
* #ORM\prePersist
*/
public function setSlugValue() {
$this->slug = $repo->createUniqueSlugForGame();
}
}
In the prePersist method, I need to ensure that the Game's slug field is unique, which requires a database query. To do the query, I need access to the EntityManager. I can get the EntityManager from inside GameRepository. So: how do I get the GameRespository from a Game?
You actually can get the repository in your entity and only during a lifecycle callback. You are very close to it, all you have to do is to receive the LifecycleEventArgs parameter.
Also see http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html
use Doctrine\ORM\Event\LifecycleEventArgs;
/**
* #ORM\Entity(repositoryClass="...\GameRepository")
* #ORM\HasLifecycleCallbacks()
*/
class Game {
/**
* #ORM\prePersist
*/
public function setSlugValue( LifecycleEventArgs $event ) {
$entityManager = $event->getEntityManager();
$repository = $entityManager->getRepository( get_class($this) );
$this->slug = $repository->createUniqueSlugForGame();
}
}
PS. I know this is an old question, but I answered it to help any future googlers.
You don't. Entities in Doctrine 2 are supposed to not know of the entity manager or the repository.
A typical solution to the case you present would be to add a method to the repository (or a service class) which is used to create (or called to store) new instances, and also produces a unique slug value.
you can inject the doctrine entity manager in your entity
(using JMSDiExtraBundle)
and have the repository like this:
/**
* #InjectParams({
* "em" = #Inject("doctrine.orm.entity_manager")
* })
*/
public function setInitialStatus(\Doctrine\ORM\EntityManager $em) {
$obj = $em->getRepository('AcmeSampleBundle:User')->functionInRepository();
//...
}
see this : http://jmsyst.com/bundles/JMSDiExtraBundle/1.1/annotations
In order to keep the logic encapsulated without having to change the way you save the entity, instead of the simple prePersist lifecycle event you will need to look at using the more powerful Doctrine events which can get access to more than just the entity itself.
You should probably look at the DoctrineSluggableBundle or StofDoctrineExtensionsBundle bundles which might do just what you need.

Zend Framework: How to start PHPUnit testing Forms?

I am having trouble getting my filters/validators to work correctly on my form, so I want to create a Unit test to verify that the data I am submitting to my form is being filtered and validated correctly.
I started by auto-generating a PHPUnit test in Zend Studio, which gives me this:
<?php
require_once 'PHPUnit/Framework/TestCase.php';
/**
* Form_Event test case.
*/
class Form_EventTest extends PHPUnit_Framework_TestCase
{
/**
* #var Form_Event
*/
private $Form_Event;
/**
* Prepares the environment before running a test.
*/
protected function setUp ()
{
parent::setUp();
// TODO Auto-generated Form_EventTest::setUp()
$this->Form_Event = new Form_Event(/* parameters */);
}
/**
* Cleans up the environment after running a test.
*/
protected function tearDown ()
{
// TODO Auto-generated Form_EventTest::tearDown()
$this->Form_Event = null;
parent::tearDown();
}
/**
* Constructs the test case.
*/
public function __construct ()
{ // TODO Auto-generated constructor
}
/**
* Tests Form_Event->init()
*/
public function testInit ()
{
// TODO Auto-generated Form_EventTest->testInit()
$this->markTestIncomplete(
"init test not implemented");
$this->Form_Event->init(/* parameters */);
}
/**
* Tests Form_Event->getFormattedMessages()
*/
public function testGetFormattedMessages ()
{
// TODO Auto-generated Form_EventTest->testGetFormattedMessages()
$this->markTestIncomplete(
"getFormattedMessages test not implemented");
$this->Form_Event->getFormattedMessages(/* parameters */);
}
}
so then I open up terminal, navigate to the directory, and try to run the test:
$ cd my_app/tests/unit/application/forms
$ phpunit EventTest.php
Fatal error: Class 'Form_Event' not found in .../tests/unit/application/forms/EventTest.php on line 19
So then I add a require_once at the top to include my Form class and try it again. Now it says it can't find another class. I include that one and try it again. Then it says it can't find another class, and another class, and so on. I have all of these dependencies on all these other Zend_Form classes. What should I do? How should I go about testing my Form to make sure my Validators and Filters are being attached correctly, and that it's doing what I expect it to do. Or am I thinking about this the wrong way?
you have to use your Zend Framework Application Configuration altough for your Unittests. If you work with the "XML" Config of PHPUnit add an Bootstrap File wich runs before the tests are executed.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="TestConfig.php">
<testsuite name="XY">
<directory>./</directory>
</testsuite>
</phpunit>
In your TestConfig.php setup the AutoLoader and other needed ressources, or use the config.ini from your Application like in my example.
$includeConfig = parse_ini_file(TEST_PATH . '/config/config.ini', true);
set_include_path(
implode(PATH_SEPARATOR, $includeConfig['includes'])
. PATH_SEPARATOR
. TEST_PATH . PATH_SEPARATOR
. get_include_path()
);
unset($includeConfig);
require_once 'Zend/Loader/Autoloader.php';
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->registerNamespace('App_');
If you need more hints check out this Tutorial on Zend Framework with PHPUNIT
PHPUnit + Zend Framework