Doctrine ORM create method phpspec test failure - orm

I try to write, at first glance, it would seem a trivial test for my repository's "update" method:
<?php
declare(strict_types=1);
namespace Paneric\Authorization\ORM\Repository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\ORMException;
use Paneric\Authorization\DTO\FieldDTO;
use Paneric\Authorization\ORM\Entity\Field;
use Doctrine\ORM\EntityRepository;
use Paneric\Authorization\Interfaces\FieldRepositoryInterface;
class FieldRepository extends EntityRepository implements FieldRepositoryInterface
{
const ENTITY_CLASS = Field::class;
public function __construct(EntityManagerInterface $_em)
{
parent::__construct($_em, $_em->getClassMetadata(self::ENTITY_CLASS));
}
...
public function update(int $fieldId, FieldDTO $fieldDTO): void
{
try {
$field = $this->find($fieldId);
$field->transfer($fieldDTO);
$this->_em->flush();
} catch (ORMException $e) {
echo $e->getMessage();
}
}
...
}
with a spec method:
<?php
namespace spec\Paneric\Authorization\ORM\Repository;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\QueryBuilder;
use Paneric\Authorization\DTO\FieldDTO;
use Paneric\Authorization\ORM\Entity\Field;
use Paneric\Authorization\ORM\Repository\FieldRepository;
use Doctrine\ORM\AbstractQuery;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
class FieldRepositorySpec extends ObjectBehavior
{
public function let(EntityManagerInterface $_em, ClassMetadata $classMetadata)
{
$_em->getClassMetadata(Field::class)->willReturn($classMetadata);
$this->beConstructedWith($_em);
}
...
public function it_updates(Field $field, FieldDTO $fieldDTO, EntityManagerInterface $_em)
{
$fieldId = 1;
$field = $this->find($fieldId);
$field->transfer($fieldDTO)->shouldBeCalled();
$_em->flush()->shouldBeCalled();
$this->update($fieldId, $fieldDTO);
}
...
}
and receive the following error:
Unexpected method call on Double\EntityManagerInterface\EntityManagerInterface\P1:
- find(
null,
1,
null,
null
)
expected calls were:
- getClassMetadata(
exact("Paneric\Authorization\ORM\Entity\Field")
)
- find(
exact("Paneric\Authorization\ORM\Entity\Field"),
exact(1)
)
- flush(
)
Apparently issue is related to the call:
...
$field = $this->find($fieldId);
...
Although the second remark related to getClassMetadata, looks strange, considering the fact that my spec let method:
public function let(EntityManagerInterface $_em, ClassMetadata $classMetadata)
{
$_em->getClassMetadata(Field::class)->willReturn($classMetadata);
$this->beConstructedWith($_em);
}
does its job in case of other spec tests.
Can anyone help me to solve this issue ? Thx in advance.

In my repository's "update" metod, line:
$field = $this->find($fieldId);
has to be replaced by:
$field = $this->_em->find(Field::class, $fieldId);
so the complete spec test looks like:
public function it_updates(Field $field, FieldDTO $fieldDTO, EntityManagerInterface $_em)
{
$fieldId = 1;
$_em->find(Field::class, $fieldId)->willReturn($field);
$field->transfer($fieldDTO)->shouldBeCalled();
$_em->flush()->shouldBeCalled();
$this->update($fieldId, $fieldDTO);
}

Related

Symfony 5 use getDoctrine() in another Controller

I try to call "class CltvController" from another class like this :
class StatLtvcController extends AbstractController
{
$cltv_temp = new CltvController();
return $this->render('admin/statltvc.html.twig', [ 'cltv_temp' => $cltv_temp->cltv(), ]);
}
but this class :
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use App\Entity\Game;
use App\Entity\Adventure;
use Symfony\Component\Routing\Annotation\Route;
class CltvController extends AbstractController
{
public function cltv(): float{
$periodh = '2021-06-01'; // $request->request->get('')
$periodi = '2021-07-31'; // $request->request->get('')
$em = $this->getDoctrine()->getManager();
$con = $em->getRepository(Game::class);
$con3 = $em->getRepository(Adventure::class);
$ncnt[] = $con->findByCountncn($periodh,$periodi);
$nadvt[] = $con3->findByCountadv($periodh,$periodi);
return $nadvt[0][0][1]/$ncnt[0][0][1];
}
}
is returning this error :
Call to a member function has() on null
Error
in G:\Mes_TPs\TP_Symfony_PHP\Quaestyo\vendor\symfony\framework-bundle\Controller \AbstractController.php (line 345)
*
* #throws \LogicException If DoctrineBundle is not available
*/
protected function getDoctrine(): ManagerRegistry
{
if (!$this->container->has('doctrine')) {
throw new \LogicException('The DoctrineBundle is not registered in your application. Try running "composer require symfony/orm-pack".');
}
return $this->container->get('doctrine');
}
I don't understand why $this->getDoctrine is returning an error?
Try to add this bloc over CltvController class:
/**
* #method getDoctrine()
*/
class CltvController extends AbstractController {
• If that didn't work, can you tell me the exact version of php & symfony of your project please?
Thanks for your answer. It's the same error message with your solution.Actually, Symfony is calling getDoctrine() in the class StatLtvcController. (i didn't put all because code was too long). How could i call getdoctrine() in the class CltvController ?
I use last versions : PHP 7.4.9 and Symfony 5.2.14

How to fix this DEPRECATION error in codeception?

I am using codeception,when I try to check dbconnection it shows the error:
> DEPRECATION: Calling the
> "Symfony\Component\EventDispatcher\EventDispatcherInterface::dispatch()"
> method with the event name as first argument is deprecated since
> Symfony 4.3, pass it second and provide the event object first
> instead.
> C:\xampp\htdocs\affiliate_codeception\codeception\vendor\symfony\event-dispatcher\EventDispatcher.php:58"
How do I fix this?
<?php
class adminTest extends \Codeception\Test\Unit
{
/**
* #var \UnitTester
*/
protected $tester;
protected function _before()
{
}
protected function _after()
{
}
// tests
public function testSomeFeature()
{
}
public function tryToTest(UnitTester $I)
{
$I->amConnectedToDatabase('testdb');
//$I->seeInDatabase('users', ['name' => 'Davert', 'email' => 'davert#mail.com']);
}
}
Change the code in vendor/codeception/phpunit-wrapper/src/Listener.php:
Search for
dispatcher->dispatch(
For each of them, swap the first and second arguments.
For example, the first occurrence is:
public function startTestSuite(\PHPUnit\Framework\TestSuite $suite)
{
$this->dispatcher->dispatch('suite.start', new SuiteEvent($suite));
}
Change it to:
public function startTestSuite(\PHPUnit\Framework\TestSuite $suite)
{
$this->dispatcher->dispatch(new SuiteEvent($suite), 'suite.start');
}

Laravel Testing Error

I just started with learning how to test within Laravel. I came across some problems though..
I'm testing my controller and want to check if a View has a variable assigned.
My controller code:
class PagesController extends \BaseController {
protected $post;
public function __construct(Post $post) {
$this->post = $post;
}
public function index() {
$posts = $this->post->all();
return View::make('hello', ['posts' => $posts]);
}
}
And my view contains a foreach loop to display all posts:
#foreach ($posts as $post)
{{post->id}}
#endforeach
Last but not least my test file:
class PostControllerTest extends TestCase {
public function __construct()
{
// We have no interest in testing Eloquent
$this->mock = Mockery::mock('Eloquent', 'Post');
}
public function tearDown()
{
Mockery::close();
}
public function testIndex() {
$this->mock->shouldReceive('all')->once()->andReturn('foo');
$this->app->instance('Post', $this->mock);
$this->call('GET', '/');
$this->assertViewHas('posts');
}
}
Now comes the problem, when I run "phpunit" the following error appears:
ErrorException: Invalid argument supplied for foreach()
Any ideas why phpunit returns this error?
Your problem is here:
$this->mock->shouldReceive('all')->once()->andReturn('foo');
$this->post->all() (which is what you're mocking) should return an array, and that's what your view expects. You're returning a string.
$this->mock->shouldReceive('all')->once()->andReturn(array('foo'));
should take care of the error you have, though you'll then get an error of the "Getting property of non-object" type.
You could do this:
$mockPost = new stdClass();
$mockPost->id = 1;
$this->mock->shouldReceive('all')->once()->andReturn(array($mockpost));
You should mock the view as well:
public function testIndex() {
$this->mock->shouldReceive('all')->once()->andReturn('foo');
$this->app->instance('Post', $this->mock);
View::shouldReceive('make')->with('hello', array('posts', 'foo'))->once();
$this->call('GET', '/');
}

Testing in Silex (mock closures) using PHPUnit

I started working with Silex and it's just great. The problem appears when trying to proper unit test my classes. Concretely the closures :(
In the following lines I explain my problem to see if any of you knows how to solve it.
Please, do not focus on the syntax but the testing problem itself.
I have a provider like this:
<?php
namespace Foo\Provider;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Foo\Bar;
class BarProvider implements ServiceProviderInterface {
public function register( Application $app ) {
$app[ 'foo_bar' ] = $app->protect( function() use ( $app ) {
return new Bar( $app );
} );
}
public function boot( Application $app ) {}
}
Then I need to get an instance of the foo_bar element:
<?php
namespace Foo;
use Silex\Application;
class Clazz {
protected $bar;
public function __construct( Application $app ) {
$this->bar = $app[ 'foo_bar' ]();
}
}
This works just fine. The thing is that I'm developing using TDD (and PHPUnit) and It's impossible for me to proper test the Clazz class.
<?php
namespace Foo\Test;
use PHPUnit_Framework_TestCase;
use Silex\Application;
use Foo\Bar;
use Foo\Clazz;
class ClazzTest extends PHPUnit_Framework_TestCase {
public function testConstruct() {
$mock_bar = $this->getMock( 'Foo\Bar' );
$mock_app = $this->getMock( 'Silex\Application' );
$mock_app
->expects( $this->once() )
->method( 'offsetGet' )
->with( 'foo_bar' )
->will( $this->returnValue( $mock_bar ) );
new Class( $mock_app );
}
}
The problem here resides in the "()" after the $app[ 'foo_bar' ] in the Clazz class.
When trying to execute the test I get a "PHP Fatal error: Function name must be a string in ..." error.
I understand I cannot unit test the class this way but I don't see the proper way to do it.
How could I test this statement (because at the end the only complex statement is $this->bar = $app 'foo_bar' ; )?
Ok, I think I managed to test properly this closure! The final test looks like this:
<?php
namespace Foo\Test;
use PHPUnit_Framework_TestCase;
use Silex\Application;
use Foo\Bar;
use Foo\Clazz;
class ClazzTest extends PHPUnit_Framework_TestCase {
public function testConstruct() {
$mock_bar = $this->getMock( 'Foo\Bar' );
$mock_app = $this->getMock( 'Silex\Application' );
$mock_app
->expects( $this->once() )
->method( 'offsetGet' )
->with( 'foo_bar' )
->will( $this->returnValue( function() use( $mock_bar ) { return $mock_bar; } ) );
new Class( $mock_app );
}
}
Instead of returning the mock, I return a closure that returns the mock. This way I don't get the error while still working with the actual mock.
Can anyone tell me if this is a correct approach?

PHP static objects giving a fatal error

I have the following PHP code;
<?php
component_customer_init();
component_customer_go();
function component_customer_init()
{
$customer = Customer::getInstance();
$customer->set(1);
}
function component_customer_go()
{
$customer = Customer::getInstance();
$customer->get();
}
class Customer
{
public $id;
static $class = false;
static function getInstance()
{
if(self::$class == false)
{
self::$class = new Customer;
}
else
{
return self::$class;
}
}
public function set($id)
{
$this->id = $id;
}
public function get()
{
print $this->id;
}
}
?>
I get the following error;
Fatal error: Call to a member function set() on a non-object in /.../classes/customer.php on line 9
Can anyone tell me why I get this error? I know this code might look strange, but it's based on a component system that I'm writing for a CMS. The aim is to be able to replace HTML tags in the template e.g.;
<!-- component:customer-login -->
with;
<?php component_customer_login(); ?>
I also need to call pre-render methods of the "Customer" class to validate forms before output is made etc.
If anyone can think of a better way, please let me know but in the first instance, I'd like to know why I get the "Fatal error" mentioned above.
Well, I think your Customer::getInstance() method is flawed. It should look like this:
...
static function getInstance()
{
if(self::$class == false)
{
self::$class = new Customer;
return self::$class; // ADDED!!
}
else
{
return self::$class;
}
}
....
In the if(self::$class == false) branch you are creating the instance of the class, but you dont return it.
You could also rewrite it as such:
static function getInstance()
{
if(self::$class == false)
{
self::$class = new Customer;
}
return self::$class;
}
To make it a bit shorter.
DRY: Don't Repeat Yourself
static function getInstance()
{
if(self::$class == false)
{
self::$class = new Customer;
}
return self::$class;
}
And for Sinlgetons it is also important to prevent __clone() from being used. Making it private should solve that problem:
private function __clone() {}