Zend Framework: How to start PHPUnit testing Forms? - unit-testing

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

Related

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');
}
}

How to Mock EntityManager in a serviceTest with Symfony?

Sorry my question is very long.
How to mock entityManager in a service test extending KernelTestCase ?
Now, the explanation and my tests...
I am using Symfony3.2. My Application is standard. I have some Controller and I use WebTestCase to test them.
Generaly, my Controller verify parameters, call a service/a manager, handle some variables and push them to view and my test are pretty simple in test extending WebTestCase.
/**
* Test New Game Action
*/
public function testFooAction(){
//We mock the Service
$fooService = $this
->getMockBuilder(GameService::class)
->disableOriginalConstructor()
->getMock();
$fooService->expects(self::once())
->method('barMethod')
->willReturn($result);
//We create the client
$client = static::createClient();
$container = $client->getContainer();
//I put my mock here
$container->set('app.game-service', $fooService);
//I launch the request
$client->request('GET', '/foo');
//I handle the response
$response = $client->getResponse();
//I do some tests like this one
self::assertEquals(200, $response->getStatusCode());
}
As you can see, I do not call EntityManger, because I use Services and these lines to put my Services's Mock
//We create the client
$client = static::createClient();
$container = $client->getContainer();
//I put my mock here
$container->set('app.game-service', $fooService);
I have a problem to mock Entity Manager in my services. My Controller is tested but not My Service.
Here is the constructor initialized a simple protected property entityManager. The problem is this protected as you will see further...
/**
* FooService constructor.
* #param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
To Test my Service, here is my initial code :
<?php
class FooServiceTest extends KernelTestCase
{
/**
* Foo Service.
*
* #var FooService
*/
private $fooService;
/**
* Prepares the environment before running each test.
*/
protected function setUp()
{
parent::setUp();
self::bootKernel();
$this->fooService = static::$kernel->getContainer()
->get('app.foo-service') //HERE IS HOW I HANDLE MY SERVICE TO TEST IT
;
}
testStart Works perfectly, there is some database interaction.
I know that I can rollback data during test. But I want to Mock entityManager to verify the call of commit method.
I try this to mock entity manager in my setUp :
protected function setUp()
{
parent::setUp();
$entityManager = $this
->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();
$entityManager
->expects(once()) // I WANT EXACTLY ONE CALL TO COMMIT METHOD
->method('commit')
->willReturn(null);
self::bootKernel();
$container = static::$kernel->getContainer();
$container->set('doctrine.orm.entity_manager', $entityManager); // THIS LINE DOES NOTHING <=======
$this->gameService = static::$kernel->getContainer()
->get('app.game-service')
;
Thes code doesn't work. Mock is not in place. I still have the true entityManager. I think it is because the container is already closed. Do it is nut usefull to set
Like a Barbarian, I change the entityManager property to public
And I do that :
protected function setUp()
{
parent::setUp();
$entityManagerMock = $this
->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();
$entityManagerMock
->expects(once()) // I WANT EXACTLY ONE CALL TO commit METHOD
->method('commit')
->willReturn(null);
self::bootKernel();
$this->gameService = static::$kernel->getContainer()
->get('app.game-service')
;
$this->gameService->entityManager = entityManagerMock;
It works perfectly. Test can be run. But it is NOT a good practice to have an entityManager in a public property
My question is : How to mock entityManager in a service test ?
(Sorry, I am not fluent in english)
First of all in your code
$container->set('doctrine.orm.entity_manager'); // THIS LINE DOES NOTHING <=======
I'm sure you missed second parameter :)
Another note: don't mock what you don't own.
In future you will run composer update and EntityManager's commit will have some optional isReallyCommit parameter. Your code will be broken, but you will not notice it, because tests are green. I understand that it very unlikely, but anyway it's just example. I think the good practice here is to
Have some adapter with entity manager incapsulated
Mock that adapter in service unit tests
Test your adapter with functional tests against real database without mocking anything
Or just don't unit test your service but make functional tests with real database interactions

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.

Models unit testing on Yii2

I'm trying to build Yii2 app through unit testing and i have some questions about it.
class UsersTest extends \Codeception\TestCase\Test
{
/**
* #var \UnitTester
*/
protected $users;
protected function _before()
{
$this->users = new \app\models\Users;
}
protected function _after()
{
}
// tests
public function testGeId()
{
}
}
When i try to run this test class i have fatal error message that Users class not found. What cause of the problem and how to solve it?
There is readme file in Yii2 tests folder which tell us to setup yii2-faker and yii2_basic_tests database. What are these two things and why i should to use them?
Thank you.
It was need to create application instance in tests/_bootstrap.php. It must be following code in that file:
require('/../vendor/autoload.php');
require('/../vendor/yiisoft/yii2/Yii.php');
$config = require('config/web.php');
(new yii\web\Application($config));
Possibly you
settings:
bootstrap: _bootstrap.php
in codeception.yml is wrong? This file include vendor/autoload.php and class names resolved
defined the auto loader in the phpunit xml configuration file
<?xml version="1.0" encoding="utf-8" ?>
<phpunit bootstrap="./vendor/autoload.php">
<testsuites>
<testsuite name="The project's test suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
</phpunit>

How can I test a Lib in CakePHP2.4?

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