PHPUnit: what does 'Attribute' refer to? - phpunit

Sorry if this is a rudimentary question, but what does the term 'Attribute' refer to in the context of PHPUnit testing? I know what properties and methods are, I know what public/private/protected do. I know the different between static and instance variables. But I see all these 'Attribute' oriented asserts in the PHPUnit command sets but none of the documentation I have seems to take the step back to describe what 'attribute' is actually referring to. properties? methods? all of the above???
SW

Properties.
The assertAttribute metods are used to test public and private properties of a class or object.
class Foo {
private $bar = 'baz';
}
class fooTest extends PHPUnit_Framework_TestCase {
// ...
public function testFooAttibute(){
$this->assertAttributeEquals(
'baz', /* expected value */
'bar', /* attribute name */
new Foo /* object */
);
}
}

class something
{
public $i_m = 'attribute';
public function i_m_method()
{
}
}
More to read: http://www.php.net/manual/en/language.oop5.properties.php

Related

Symfony 4: I decorated UrlGeneratorInterface, but it's not used, it uses CompiledUrlGenerator instead

I decorated UrlGeneratorInterface
app.decorator.url_generator:
class: App\CoreBundle\Routing\Extension\UrlGenerator
decorates: Symfony\Component\Routing\Generator\UrlGeneratorInterface
arguments: ['#app.decorator.url_generator.inner']
but it's not used in cases where some bundle in example executes $this->generator->generate(), and I tracked what Symfony does through XDebug and CompiledUrlGenerator is used instead. I can see where this happens, namely in Symfony\Component\Routing\Router in getGenerator it specifically checks for CompiledUrlGenerator::class. But I don't want to override vanilla Symfony code. How am I supposed to override/decorate/extend which class in order for mine to be chosen always, as I have special parameters I need to add to the path. Thank you in advance!
I found it.
app.decorator.router:
class: App\CoreBundle\Routing\Extension\Router
decorates: 'router.default'
arguments: ['#app.decorator.router.inner']
Decorating this actually makes all packages use your Router. And as the UrlGenerator it has the generate function which can be extended.
EDIT: On request I provide the router class as well:
class Router implements RouterInterface {
protected $innerRouter;
public function __construct(RouterInterface $innerRouter) {
$this->innerRouter = $innerRouter;
}
public function setContext(RequestContext $context)
{
$this->innerRouter->setContext($context);
}
public function getContext()
{
return $this->innerRouter->getContext();
}
public function getRouteCollection()
{
return $this->innerRouter->getRouteCollection();
}
public function generate($name, $parameters = [], $referenceType = self::ABSOLUTE_PATH)
{
//add here to $parameters...
return $this->innerRouter->generate($name, $parameters, $referenceType);
}
public function match($pathinfo)
{
$parameters = $this->innerRouter->match($pathinfo);
//add here to $parameters...
return $parameters;
}
}

Symfony 4 : Call to a member function get() on null

class EtudiantController extends AbstractController
{
private $etudiant ;
private $form ;
public function __construct()
{
$this->etudiant = new Etudiant();
$this->form = $this->createForm(EtudiantType::class, new Etudiant());
}
}
** i'v got an error when instantiate a form in a constructor using the createForm() function **
Here is the wrong way to solve your problem:
class EtudiantController extends AbstractController
{
private $form;
public function __construct(FormFactoryInterface $formFactory)
{
$this->form = $formFactory->create(TextType::class, new Etudiant());
}
}
I say it is wrong (even though it will work) because creating things like forms really should be done in individual controller actions, not hidden in the constructor. You might be trying to apply Dont Repeat Yourself (DRY) but in cases like this, Don't Confuse Your Future Self takes precedence.
And as far as why injecting the form factory is necessary, I would once again urge you to look at the Symfony source code for AbstractController as well as ControllerTrait. Understanding how dependency injection works is critical to being able to effectively use the framework.

Symfony2 : Doctrine : PHPUnit : Set entity Id during flushing with mocked entity manager in unit tests

Symfony 2.8.13 / Doctrine ORM 2.5.5 / PHPUnit 5.7.5
I want to test a method of a class that makes use of the doctrine entity manager. This public method calls a private one that instantiates a Bookmark entity, flushes it and returns this entity. Then later, in the tested method I need to access the entity Id. Everything is mocked excepted the Bookmark entity itself. The main problem is that there is no setId() method in my entity. Here is the code and my main idea to solve this issue but I don't know if it is correct ?
Tested class and method
class BookmarkManager
{
//...
public function __construct(TokenStorageInterface $tokenStorage, ObjectManager $em, Session $session)
{
//...
}
public function manage($bookmarkAction, $bookmarkId, $bookmarkEntity, $bookmarkEntityId)
{
//...
$bookmark = $this->add($bookmarkEntity, $bookmarkEntityId);
//...
$bookmarkId = $bookmark->getId();
//...
}
private function add($entity, $entityId)
{
//...
$bookmark = new Bookmark();
//...
$this->em->persist($bookmark);
$this->em->flush();
return $bookmark;
}
}
Test
class BookmarkManagerTest extends \PHPUnit_Framework_TestCase
{
public function testThatRestaurantAdditionToBookmarksIsWellManaged()
{
//...
// THIS WON'T WORK AS NO setId() METHOD EXISTS
$entityManagerMock->expects($this->once())
->method('persist')
->will($this->returnCallback(function ($bookmark) {
if ($bookmark instanceof Bookmark) {
$bookmark->setId(1);
}
}));
//...
$bookManager = new BookmarkManager($tokenStorageMock, $entityManagerMock, $sessionMock);
//...
}
}
Solutions ?
1- Make usage of reflection class as proposed here :
$entityManagerMock->expects($this->once())
->method('persist')
->will($this->returnCallback(function ($bookmark) {
if ($bookmark instanceof Bookmark) {
$class = new \ReflectionClass($bookmark);
$property = $class->getProperty('id');
$property->setAccessible(true);
$property->setValue($bookmark, 1);
//$bookmark->setId(1);
}
}));
2- Create a test Boookmark entity that extends from the real one and add a setId() method. Then create a mock of this class and replace and customize the one got from the ReturnCallback method with this one ? It seems crappy...
Any thoughts ? Thanks for your help.
The reflection looks interesting but it decreases readability of tests (mixing with mocks makes the situation tough).
I would create a fake for entity manager and implements there setting id based on reflection:
class MyEntityManager implements ObjectManager
{
private $primaryIdForPersitingObject;
public function __construct($primaryIdForPersitingObject)
{
$this->primaryIdForPersitingObject = $primaryIdForPersitingObject;
}
...
public function persist($object)
{
$reflectionClass = new ReflectionClass(get_class($object));
$idProperty = $reflectionClass->getProperty('id');
$idProperty->setAccessible(true);
$idProperty->setValue($object, $this->primaryIdForPersitingObject);
}
public function flush() { }
...
}
Once you implemented this, you can inject the instance of MyEntityManager and make your tests small and easier to maintain.
You test would look like
<?php
class BookmarkManagerTest extends \PHPUnit_Framework_TestCase
{
public function testThatRestaurantAdditionToBookmarksIsWellManaged()
{
// ...
$entityManager = MyEntityManager(1);
//...
$bookManager = new BookmarkManager($tokenStorageMock, $entityManager, $sessionMock);
//...
}
}
Of course, a situation may be harder if there is a need of setting different ids for many persisting objects. Then you can, for example, increase $primaryIdForPersitingObject on persist call
public function persist($object)
{
$reflectionClass = new ReflectionClass(get_class($object));
$idProperty = $reflectionClass->getProperty('id');
$idProperty->setAccessible(true);
$idProperty->setValue($object, $this->primaryIdForPersitingObject);
$this->primaryIdForPersitingObject++;
}
It may be extended even further to have separate primaryIdForPersitingObject each entity class, and your tests will be still clean.

Undefined variable in PHPUnit Test Class

I have a test class that reports an undefined variable and I cannot seem to understand what the issue is.
Basically the listener below is suppose to listen to an application boot event documented in the class below:
<?php
namespace Colleen\Core\Event\Application;
final class ApplicationBootedEvents
{
const APP_BOOTED = 'application.booted';
}
My event class is as shown below which receives an instance of the application itself.
<?php
namespace Colleen\Core\Event\Application;
use Symfony\Component\EventDispatcher\Event;
use Colleen\Core\Application;
/**
* The application.booted event is dispatched each time
* an application instance is created in the system.
*
*/
class ApplicationBootedEvent extends Event
{
protected $app;
public function __construct(Application $app)
{
$this->app = $app;
}
public function getApplication()
{
return $app;
}
}
These two classes to me look perfect according to Symfony's documentation on the Event Dispatcher Component. Following is the listener class that is suppose to listen to ApplicationBootedEvents::APP_BOOTED event.
<?php
namespace Colleen\Core\Event\Application\Listener;
use Colleen\Core\Event\Application\ApplicationBootedEvent;
class ApplicationBootedListener
{
public function onBoot(ApplicationBootedEvent $event)
{
$container = $event->getApplication()->getContainer();
$container->set('class.dispatcher', '\\Symfony\\Component\\EventDispatcher\\EventDispatcher');
}
}
The Listener class does nothing at the moment and my test case is to test whether the "class.dispatcher" key exist on my container which simple extends Pimple and is made available through the Application Object.
Below is my test that shows how these will eventually be used in my front controller or any class that stands between them and the front controller.
<?php
namespace Colleen\Qa\Core\Event\Application\Listener;
use Colleen\Core\Event\Application\Listener\ApplicationBootedListener;
use Colleen\Core\Event\Application\ApplicationBootedEvents;
use Colleen\Core\Event\Application\ApplicationBootedEvent;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Colleen\Core\Container\Container;
use Colleen\Core\Application;
class AppliocationBootedListenerTest extends \PHPUnit_Framework_TestCase
{
public function testApplicationBootListener()
{
$dispatcher = new EventDispatcher();
$dispatcher->addListener(
ApplicationBootedEvents::APP_BOOTED, array(
new ApplicationBootedListener(), 'onBoot'
));
$app = $dispatcher->dispatch(ApplicationBootedEvents::APP_BOOTED, new ApplicationBootedEvent(new Application(new Container())))->getApplication();
$expected = '\\Symfony\\Component\\EventDispatcher\\EventDispatcher';
$actual = $app->getContainer()->get('class.dispatcher');
$this->assertSame($expected, $actual);
}
}
The idea is to test whether the Listener gets called and if it is able to feed our application object's container with all the necesary objects we will need to get our web framework to work.
Below is the output I get as a result if running this test case.
There's an error in your ApplicationBootedEvent.php file, on line 24 as the stack trace suggested..
Change
public function getApplication()
{
return $app;
}
To
public function getApplication()
{
return $this->app;
}

Combining two identical sub classes

So I have two sub classes that extend different base classes in Flex how can I combine these so that I am not repeating myself.
Basically I have something like
public class A extends B {
// methods
}
public class C extends D {
// same methods as class A
}
any way to combine this so that I am not repeating the same code twice.
Favor composition over inheritance
So, the question is, how should you compose the solution?
One possibility is to use Decorator pattern. This is essentially a wrapper around your existing Classes. To make this work, your Classes will probably need to implement an Interface that exposes whatever you'll need to do the job.
So something like:
public interface IFoo {
function get name():String;
function set name(value:String):void;
}
public class A extends B implements IFoo {
protected var _name:String;
public function get name():String {
return _name;
}
public function set name(value:String):void {
_name = value;
}
}
public class C extends D implements IFoo {
protected var _name:String;
public function get name():String {
return _name;
}
public function set name(value:String):void {
if (_value != _name) {
_name = value;
dispatchEvent(new Event('nameChanged'));
}
}
}
public class FooDecorator {
protected var _foo:IFoo;
public function FooDecorator(foo:IFoo) {
_foo = foo;
}
public function sayName():void {
trace('foo name is', _foo.name);
}
}
Another solution is to give both A and C member variables of a fifth type that encapsulate the behavior (like what Jeffry said, but I prefer to obey the law of Demeter where possible):
class NameSayer {
function sayName(name:String):void {
trace('foo name is', _foo.name);
}
}
then
public class A extends B {
public var name:String;
public var sayer:NameSayer;
//note that this method would be identical in both Classes
//but this is OK because the underlying logic is encapsulated
//and can be easily changed
public function sayName():void {
if (sayer) {
sayer.sayName();
}
}
}
I think many developers get too hung up on zealously following DRY and, as Jeffry says, this can cause other, worse, problems in your architecture. Which, if any, of these solutions is appropriate will depend on exactly what you're trying to accomplish.
You have two child classes (extending different parents) that implement the exact same methods.
public class B {}
public class D {}
public class A extends B {
// methods
m1();
m2();
...
}
public class C extends D {
// same methods as class A
m1();
m2();
...
}
Now lets make some points about it.
In assigning a method to a class, the basic idea is that, that method or behaviour really belongs to that class - it is really a property of that class or type. For example, breathing for Animal. When this is the case, the behaviour is tied to class state (or data, or attributes, or variables). If a method does not access the class variables in any ways, then, that method may not belong there. At least it is the general rule.
Now, in your case, you have m1(), m2(), ... methods that appear in two different classes. This raises the possibility that they may not be really tied to the state of those classes. If so, then the better solution is to completely remove them into a new class.
If you do so,
You will also get rid of two classes, A and C, which now exist only for this purpose.
You get rid of two inheritance relationships. This makes you code much simpler.
And, you will achieve your objective of not repeating your self.
--
//Parent classes (child classes are now gone)
public class B {}
public class D {}
--
// Your new class
public class X {
// methods that previously were in A and C
m1();
m2();
...
}
Although, I have mixed feelings about its use; you can use the include directive.
Create a file, like this, named sharedMethods.as (or whatever you want). This is not a real class; it just includes code snippets:
public var mySharedMethod(mySharedMethodArguments:ArgumentType):void{
// do something
}
Then you can include it in your your other classes:
public class A extends B {
include "sharedMethods.as";
}
public class C extends D {
include "sharedMethods.as";
}
The code from your include file will be compiled as part of Class A and Class C.
You could also put your shared code in another class and have an instance of that class in both A and C. Then you either have to write wrapper methods or drill down the calls sort of like this:aInstance.sharedCodeObject.sharedMethod();
My intuition is that if you run into this a lot; you may have a problem with the object model that needs some refactoring.

Resources