I'm using typo3 6 with extbase and some dependency injection features.
MyClass is injected with a service. The property which holds the service is protected.
class MyClass {
/**
*
* #var \X\Y\Z\MyService
* #inject
*/
protected $myService;
}
How can I change (or mock) the service in my UnitTest by?
I use reflection api to inject mock object to a protected field. See http://php.net/manual/en/class.reflectionobject.php
Related
I'm using PhpUnit/DbUnit to create a set of 5 to 10 fixture records. I use in-memory sqlite.
I successfully can use a Doctrine\DBAL\Connection to access it, so I can use methods like ->insert( $tableName, $data ); for my tests.
Now I want to consume the Doctrine EntityManager so I can create an entity and call ->persist().
In unit-testing I used to mock the EntityManager and asserted an expectation to call persist.
But for functional-testing I want to check the final result written to the DB, even go further and re-use the result of the writing.
I therefore need to create a real EntityManager but consuming the DbUnit connection.
I've seen that creting a new EntityManager takes 3 arguments, but still the creator is protected:
/**
* Creates a new EntityManager that operates on the given database connection
* and uses the given Configuration and EventManager implementations.
*
* #param \Doctrine\DBAL\Connection $conn
* #param \Doctrine\ORM\Configuration $config
* #param \Doctrine\Common\EventManager $eventManager
*/
protected function __construct(Connection $conn, Configuration $config, EventManager $eventManager)
{
[...]
I don't know if I'm expected to create a subclass, or maybe use an already subclassed EntityManager or how should I proceed.
So question:
How can I setup a real Doctrine\ORM\EntityManager within a PhpUnit/DbUnit test class using the low level Doctrine\Dbal\Connection that is already bound to the DbUnit connection?
Note: I'm inside a symfony3 project, so mapping files are in the expected places of symfony.
Symfony 2.8 + doctrine
I have two Bundles: CoreBundle and BonusBundle
CoreBundle have folder Model containing abstract class ClassA:
use Doctrine\ORM\Mapping as ORM;
//[...]
abstract class ClassA
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
protected $name;
}
and in another directory Entity - ClassB:
//[...]
/**
* ClassB
*
* #ORM\Table()
* #ORM\Entity
*/
class ClassB extends ClassA
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
}
Currently this working well, ClassB inherit name property and this way we have mapped Entity ClassB with id and name.
I added in Model directory of BonusBundle (second one) other abstract class ClassC. Its the same as ClassA but in other bundle.
And now last key thing to my example - I added ClassD in CoreBundle (Entity directory) extending ClassC from BonusBundle (the same way as above).
My problem
In result I recived ClassB with properties id, name and ClassD only with id property.
I cannot understand why this happen. Its looks like doctrine ignore annotations if superclass lives in other Bundle. I checked some docs and other questions but I can't find understand what happening.
I see in config docs here that auto_mapping option checking Entity directory:
Doctrine's auto_mapping feature loads annotation configuration from
the Entity/ directory of each bundle and looks for other formats (e.g.
YAML, XML) in the Resources/config/doctrine directory.
and
If it wasn't possible to determine a configuration format for a
bundle, the DoctrineBundle will check if there is an Entity folder in
the bundle's root directory. If the folder exist, Doctrine will fall
back to using an annotation driver.
in my project this folder exist in both Bundles. And If symfony check only Entity folder then why first example (Model) working well?
How this mechanism works?
I tested some possibilities and I found solution to fix it but still no idea why this happen.
If I add annotation to superclass #ORM\MappedSuperclass() then mappings are loaded correctly but only if class is located in Entity directory.
use Doctrine\ORM\Mapping as ORM;
/**
* ClassA
*
* #ORM\MappedSuperclass()
*/
abstract class ClassA
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
protected $name;
}
This way my annotations are visible in other Bundles and my ClassA is not Entity itself.
Still I dont understand why it works if class exist in the same Bundle but in other directory. In addition inside FoSUserBundle exist similar example using MappedSuperclass() - FOSUserBundle/Model/User.php but its located in Model directory and still working.
//EDIT
Completion to #Boulzy answer
Probably i found answer for second part - why it can see mapping from other directory but the same bundle. After analysing other working example I found that mapped property with strict access private is not visible for child class but protected property is visible, mapped and don't need #ORM\MappedSuperclass() annotation as long as it used in the same Bundle.
It seems that #ORM\MappedSuperclass() give us possibility to map even private properties and this way they are visible and mapped for other classes in any other bundle (as long as it lives in Entity or other mapped directory).
In completion of #Griva answer about the MappedSuperClass, here is an simple example of how to tell Doctrine to look for mapped classes in other folders than Entity:
<?php
namespace AppBundle;
use Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler\DoctrineOrmMappingsPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class AppBundle extends Bundle
{
/**
* {#inheritDoc}
*/
public function build(ContainerBuilder $container)
{
parent::build($container);
// With Yaml configuration format
$container->addCompilerPass(DoctrineOrmMappingsPass::createYamlMappingDriver(array(
realpath(__DIR__ . '/Resources/config/doctrine-mapping') => 'AppBundle\Model'
)));
// With annotation configuration format
$container->addCompilerPass(DoctrineOrmMappingsPass::createAnnotationMappingDriver(array(
'AppBundle\Model'
)));
}
}
There are Doctrine MappingsPass available for MongoDB and CouchDB too.
i have just implemented my first service in Symfony2.
I noticed that, within a controller method, whether i call the service so
$this->container->get('main.service');
or so
$this->get('main.service');
there is no difference.
I get the service equally with both.
Where are the differences?
There's no difference if you're extending the Base Controller provided by Symfony.
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class YourController extends Controller
If you take a deeper look at the implementation of the Symfony\Bundle\FrameworkBundle\Controller\Controller, you may notice that it provides a get() helper which do exactly the same call as what you did first (getting your service through the container).
So, then,
There's no difference as $this->get('something') simply sencapsulates a call to $this->container->get('something').
Here's the implementation of the get() method you're calling when doing $this->get('main.service');
/**
* Gets a service by id.
*
* #param string $id The service id
*
* #return object The service
*/
public function get($id)
{
return $this->container->get($id);
}
I'm creating a simple RESTful API in PHP for practice. I'm trying to write as testable code as possible. After reading many tutorials and watching a few videos, I still feel at a loss on how to design this.
Basically, I have set up a Router class. It is responsible for mapping url paths to controller methods.
It's easy to test the router's state after adding a route.
But, how do I test if the proper class->function(params) has been called in respond()?
I'm using PHPUnit, and I've been reading about mocks. I don't know how to use them in this context.
Currently, respond() parses a given path and request method, and calls the mapped method.
Here is my current design:
private $routes;
public function __construct() {
$routes = array();
}
/**
* Gets all current routes
*/
public function getRoutes();
/**
* Sets all routes
*/
public function setRoutes($routes);
/**
* Routes GET request
*/
public function get();
/**
* Routes POST request
*/
public function post();
/**
* Routes PUT request
*/
public function put();
/**
* Routes DELETE request
*/
public function delete();
/**
* Sets up default paths for a given resource
*/
public function resource();
/**
* Respond to request
* #return mixed JSON of resource data
*/
public function respond($req_method, $request);
/**
* Returns mapped call info from request method and path
* #return mixed An array of the call and params
*/
private function parse($req_method, $request);
As the comments have indicated, this would be a good use of a spy or mocking system. PHPunit has some ability to create and test for mocks, but I prefer to use a different library - Mockery.
This code will create a class and test that that when you call average(), it's called three times, and then also returns a given value.
Your code would call respond(), after setting up a mock that shouldReceive('get')->once() (for example). The m::close in the teardown will verify that get() was called, just one time, and would fail the test if it was not.
<?php
use \Mockery as m;
class TemperatureTest extends PHPUnit_Framework_TestCase
{
public function tearDown()
{
m::close();
}
public function testGetsAverageTemperatureFromThreeServiceReadings()
{
$service = m::mock('service');
$service->shouldReceive('readTemp')->times(3)->andReturn(10, 12, 14);
$temperature = new Temperature($service);
$this->assertEquals(12, $temperature->average());
}
}
Since you would be calling a real class to do work in respond(), you will need a 'partial mock'
$restful= m::mock('RestfulController[get]');
$restful->shouldReceive('get')->once();
I'm currently learning the new Java EE 6 component models and am confused with the latest dependency injection mechanism. So here are my questions:
1) What is the difference between #Inject and #EJB
2) If I have a simple POJO that contains another POJOs (which one of them is the DAO code), what would be the better choice: #Inject or #EJB?
Can I mix #Inject and #EJB?
An example would be:
ClassA implements InterfaceA and has
an instance of ClassA_Adaptor
ClassA_Adaptor implements InterfaceAB
and has an instance of ClassB
ClassB implements InterfaceB and has
an instance of ClassB_Adaptor and an
instance DAO_ClassB
ClassB_Adaptor implements InterfaceB
and has an instance of ClassC
ClassC implements InterfaceBC and has
an instance of WebService_ClassC
DAO_ClassB will use JPA 2.0
(#PersistenceContext)
I'd like to inject all of them including the DAO and the WebService.
3) Is it a bad approach to only use transactional for certain operations but not for all?
As an example: Some methods in DAO_ClassB are your typical query, while other methods are "write" methods. Is it bad to not wrap the "READ" methods with transaction?
To my understanding, the DAO_ClassB can be wrapped with transaction using #EJB (inject the DAO_ClassB and make all methods transactional). How can I control it?
Sorry if some of the questions are confusing because I know only bits and pieces of the Java EE 6 new component model.
#EJB injects EJBs only, but #Inject can be used to inject POJOs rather than EJBs. However, #Inject requires that your archive be a BDA (contain beans.xml for EE 6, or implicitly in EE 7). #Inject also has additional CDI-specific capabilities (scopes, interceptors, etc.), but those capabilities incur extra overhead. Application servers have support for specifying #EJB bindings so that a deployer can choose the target EJB, but #Inject only allows the application developer to choose the target EJB (and it must exist in the application).
If the target is not an EJB, then you must not use #EJB.
It depends whether you're making multiple inter-related queries and then attempting to make business decisions. You need to understand isolation levels and take them into consideration, even for read-only operations.
From Adam Biens Weblog:
You can use both annotations to inject EJBs. Start with #Inject and if you encounter any problems, switch to #EJB.
#Inject does not have any methods / attributes--it is just a plain annotation:
#Target(value = {ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
#Retention(value = RetentionPolicy.RUNTIME)
#Documented
public #interface Inject {
}
On the other hand, the #EJB annotation allows you to pass additional information, which could be useful to reference remote EJBs, or EJBs which cannot be simple injected in the "Convention over Configuration" style:
#Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
#Retention(value = RetentionPolicy.RUNTIME)
public #interface EJB {
public String name() default "";
public String beanName() default "";
public Class beanInterface() default Object.class;
public String mappedName() default "";
}
#Inject is more general than EJB and is part of CDI specification. So if you want to use #Inject, you need an implementation of it in your server.
For POJOs (not EJBs) you have to use #Inject.