getRepository is null in phpunit test - symfony

I'm running phpunit tests on some classes and I get this error
Call to a member function getRepository() on null in
src/MyApp/MyBundle/CopyList.php on line 429
At that line is
$list = $this->em->getRepository('MyAppMyBundle:CopyList')->findByName($task);
from
namespace MyApp\MyBundle\Classes\Action;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ParameterBag;
use MyApp\MyBundle\Entity\CopyVirtualList;
use Doctrine\ORM\EntityManager;
class CopyList extends Action
{
private $em;
public function __construct(EntityManager $em)
{
$this->em = $em;
}
public function __clone() {
$task = $this->getTask();
$this->__copy($task);
}
public function __copy($task)
{
$list = $this->em->getRepository('MyAppMyBundle:CopyList')->findByName($task);
if (!$list) {
$list = new CopyVirtualList();
$this->em->persist($list);
$this->em->flush();
}
}
}
which is being called from the line
$clone = clone $container;
in
namespace tests\src\MyApp\MyBundle\Classes;
use Symfony\Component\HttpFoundation\Request;
abstract class TaskContextContainerTestCase extends TestCase
{
public function testCloning()
{
$container = $this->createInstance();
$container->setImmutable(true);
$this->assertTrue($container->isImmutable());
$clone = clone $container;
$this->assertNotEquals($container, $clone);
$this->assertFalse($clone->isImmutable());
}
protected function createInstance()
{
$task = $this->getMockBuilder('MyApp\MyBundle\Model\TaskContext')
->disableOriginalConstructor()
->getMockForAbstractClass();
$container = $task->createElement(
$this->getContainerKind(),
$this->getContainerType()
);
$container->setContext($task);
return $container;
}
}
TestCase is
namespace tests\src\MyApp\MyBundle;
use MyApp\Environment as Env;
require_once dirname(__DIR__) . '/../../../../app/AppKernel.php';
class TestCase extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
try {
$kernel = new \AppKernel('test', true);
$kernel->boot();
new \MyApp\Environment(); // init single env-instance
Env::getInstance()->setContainer($kernel->getContainer());
} catch (\Exception $e) {
}
parent::setUp();
}
}
And
namespace MyApp\MyBundle\Tests\Units\Classes\Action;
use MyApp\MyBundle\Classes\Action\CopyList;
use tests\src\MyApp\MyBundle\Classes\Action\ActionTestCase as TestCase;
class CopyListTest extends TestCase {
private $object;
public function setUp()
{
parent::setUp();
$task = $this->getMockBuilder('MyApp\MyBundle\Model\TaskContext')
->disableOriginalConstructor()
->getMock();
$this->object = new CopyList($task);
}
public function testCreateInstance() {
$task = $this->getMockBuilder('MyApp\MyBundle\Model\TaskContext')
->disableOriginalConstructor()
->getMockForAbstractClass();
$container = $task->createElement($this->getContainerKind(), $this->getContainerType());
$container->setContext($task);
return $container;
}
public function testCloning()
{
$container = $this->createInstance();
$container->setImmutable(true);
$this->assertTrue($container->isImmutable());
$clone = clone $container;
$this->assertNotEquals($container, $clone);
$this->assertFalse($clone->isImmutable());
}
}
Can anyone point me in the right direction?

Related

Symfony EasyAdminBundle event pre_update triggered twice

I've created an event subscriber that sends an email with Swiftmailer every time certain entity is updated but the event is triggered twice so i'm receiving email two times.
I've followed this guide and this one. The event is: easy_admin.pre_update
EasyAdminBundle version: 1.17.9
services.yml
app.easy_admin.aprobar_publicacion:
class: AppBundle\EventListener\AprobarPublicacionSubscriber
arguments: ['#mailer','#service_container','#twig']
tags:
- { name: kernel.event_subscriber, event: easy_admin.pre_update, method: preUpdate }
AprobarPublicacionSubscriber.php
<?php
namespace AppBundle\EventListener;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use AppBundle\Entity\VestidoDeNovia;
use AppBundle\Entity\PlantillaEmail;
class AprobarPublicacionSubscriber implements EventSubscriberInterface {
protected $mailer;
protected $container;
protected $twig;
public static function getSubscribedEvents() {
return array(
'easy_admin.pre_update' => array('preUpdate'),
);
}
public function __construct(\Swift_Mailer $mailer, \Symfony\Component\DependencyInjection\ContainerInterface $container, \Twig_Environment $twig) {
$this->mailer = $mailer;
$this->container = $container;
$this->twig = $twig;
}
public function preUpdate(GenericEvent $event) {
$entity = $event->getSubject();
if (!($entity instanceof VestidoDeNovia)) {
return;
}
$uow = $event->getArgument('em')->getUnitOfWork();
$uow->computeChangeSets();
$changeset = $uow->getEntityChangeSet($entity);
if (array_key_exists('estado', $changeset)) {
$estadoActual = $changeset['estado'][0]->getId();
if ($estadoActual != 2 and $entity->getEstado()->getId() == 2) {
$plantillaEmail = new PlantillaEmail();
$plantillaEmail = $event->getArgument('em')->getRepository(PlantillaEmail::class)->find(6);
$message = (new \Swift_Message($plantillaEmail->getAsunto()))
->setFrom($this->container->getParameter('direccion_mail_sistema'))
->setTo($entity->getUsuario()->getEmail())
->setBody(
$this->twig->render(
'AppBundle::Emails/publicacion_exitosa.html.twig', array(
'titulo' => $plantillaEmail->getAsunto(),
'mensaje' => $plantillaEmail->getMensaje(),
)
), 'text/html'
)
;
$this->mailer->send($message);
}
}
}
}
What am i missing?

Symfony mock service when test console command

How to mock some service when test console command. I have some console command, in this command I get some service and I want mock this service
console command
const APP_SATISFACTION_REPORT = 'app:satisfactionrepor';
protected function configure()
{
$this
->setName(self::APP_SATISFACTION_REPORT)
->setDescription('Send Satisfaction Report');
}
/**
* #param InputInterface $input
* #param OutputInterface $output
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$container = $this->getContainer();
$serviceCompanyRepo = $container->get('app.repository.orm.service_company_repository');
$satisfactionReport = $container->get('app.services.satisfaction_report');
/** #var ServiceCompany $serviceCompany */
foreach ($serviceCompanyRepo->findAll() as $serviceCompany) {
try {
$satisfactionReport->sendReport($serviceCompany);
} catch (\Exception $e) {
$io->warning(sprintf(
'Failed to send satisfaction report for service company with ID %s',
$serviceCompany->getId()
));
}
}
}
and my tests
/** #var Console\Application $application */
protected $application;
protected $container;
/** #var BufferedOutput $output */
protected $output;
/**
* #var ServiceCompanyRepository
*/
private $serviceCompanyRepository;
prepare console command
public function setUp()
{
parent::setUp();
$entityManager = $this->getEntityManager();
$this->serviceCompanyRepository = $entityManager->getRepository(ServiceCompany::class);
static::bootKernel();
$this->container = static::$kernel->getContainer();
$this->application = new Console\Application(static::$kernel);
$this->application->setAutoExit(false);
$master = new SatisfactionReportCommand();
$this->application->add($master);
}
public function setUpMaster() {
$this->output = new BufferedOutput();
$this->application->run(new ArgvInput([
'./bin/console',
SatisfactionReportCommand::APP_SATISFACTION_REPORT,
]), $this->output);
}
public function testGetMasterOutput()
{
$this->loadFixture(ServiceCompany::class);
/** #var ServiceCompany[] $serviceCompanies */
$serviceCompanies = $this->serviceCompanyRepository->findAll();
$this->assertCount(2, $serviceCompanies);
$client = self::createClient();
mock service app.services.satisfaction_report
$service = $this->getMockService($serviceCompanies);
and set it in container
$client->getContainer()->set('app.services.satisfaction_report', $service);
$this->setUpMaster();
$output = $this->output->fetch();
}
protected function getMockService($serviceCompanies)
{
$service = $this->getMockBuilder(SatisfactionReport::class)
->setMethods(['sendReport'])
->disableOriginalConstructor()
->getMock();
$service
->expects($this->exactly(2))
->method('sendReport')
->withConsecutive(
[$serviceCompanies[0]],
[$serviceCompanies[1]]
);
return $service;
}
How to mock app.services.satisfaction_report? Set in container app.services.satisfaction_report not help me
I had same problem but I resolved it.
I have base class:
class TestCase extends WebTestCase
{
/** #var Application */
private $application;
private $mailServiceMock;
protected function setMailService(MailService $mailServiceMock): void
{
$this->mailServiceMock = $mailServiceMock;
}
protected function getApplication(): Application
{
static::bootKernel();
static::$kernel->getContainer()->get('test.client');
$this->setMocks();
$this->application = new Application(static::$kernel);
$this->application->setCatchExceptions(false);
$this->application->setAutoExit(false);
return $this->application;
}
protected function execute(string $action, array $arguments = [], array $inputs = []): CommandTester
{
$tester = (new CommandTester($this->getApplication()->find($action)))->setInputs($inputs);
$tester->execute($arguments);
return $tester;
}
private function setMocks(): void
{
if ($this->mailServiceMock) {
static::$kernel->getContainer()->set('mail', $this->mailServiceMock);
}
}
}
And test class
class SendEmailCommandTest extends TestCase
{
public function testExecuteSendingError(): void
{
$mailServiceMock = $this->getMockBuilder(MailService::class)->disableOriginalConstructor()
->setMethods(['sendEmail'])->getMock();
$mailServiceMock->method('sendEmail')->willThrowException(new \Exception());
$this->setMailService($mailServiceMock);
$tester = $this->execute(SendEmailCommand::COMMAND_NAME, self::NORMAL_PAYLOAD);
$this->assertEquals(SendEmailCommand::STATUS_CODE_EMAIL_SENDING_ERROR, $tester->getStatusCode());
}
}
As you can see I set mail service right after booting kernel.
And here you can see my services.yaml:
services:
mail.command.send.email:
autowire: true
class: App\Command\SendEmailCommand
arguments: ["#logger", "#mail"]
tags:
- {name: console.command, command: "mail:send.email"}
If you create the commands as a service, where the framework injects the services automatically (either autowired, or with an explicit argument list) into a constructor (tip: in the command, call the parent::__construct()), then the test can create whatever mock or other replacement service that matches the parameter typehint (or interface).
here is my example class:
class MainCommandTest extends IntegrationTestCase
{
/**
* #var MainCommand
*/
protected $subject;
/**
* #var Application
*/
protected $application;
/**
* sets test subject
*
* #return void
*/
public function setUp()
{
parent::setUp();
static::bootKernel();
$readStreams = new ReadStreams();
$udpStreamMock = $this->getMockBuilder(UdpStream::class)->disableOriginalConstructor()->setMethods(['readIncomingStreams'])->getMock();
$udpStreamMock->expects($this->once())->method('readIncomingStreams')->willReturn($readStreams);
static::$kernel->getContainer()->set(UdpStream::class, $udpStreamMock);
$application = new Application($this::$kernel);
$this->subject = $this->getService(MainCommand::class);
$application->add( $this->subject);
$this->application = $application;
}
/**
* Tests command in $subject command,
*
* #return void
*/
public function testCommand()
{
$command = $this->application->find( $this->subject->getName());
$commandTester = new CommandTester($command);
$commandTester->execute(
[
'command' => $this->subject->getName()
]
);
$this->stringContains($commandTester->getDisplay(true), 'finished');
$this->assertEquals($commandTester->getStatusCode(), 0);
}
}

Symfony 2 : How to render a template outside a controller or in a service?

How to render a template outside a controller or in a service?
I've been following the documentation of Symfony2. Doc
namespace Acme\HelloBundle\Newsletter;
use Symfony\Component\Templating\EngineInterface;
class NewsletterManager
{
protected $mailer;
protected $templating;
public function __construct(
\Swift_Mailer $mailer,
EngineInterface $templating
) {
$this->mailer = $mailer;
$this->templating = $templating;
}
// ...
}
This is where i call my helper :
$transport = \Swift_MailTransport::newInstance();
$mailer = \Swift_Mailer::newInstance($transport);
$helper = new MailHelper($mailer);
$helper->sendEmail($from, $to, $subject, $path_to_twig, $arr_to_twig);
So the first thing here missing is the second parameter of the construct method in :
$helper = new MailHelper($mailer);
But how would i instantiate the EngineInterface?
Of course it can't be :
new EngineInterface();
I'm totally lost here.
All what i need to do is render a template for the email that is being sent.
Inject only #twig and pass the rendered template to the mailer body:
<?php
namespace Acme\Bundle\ContractBundle\Event;
use Acme\Bundle\ContractBundle\Event\ContractEvent;
class ContractListener
{
protected $twig;
protected $mailer;
public function __construct(\Twig_Environment $twig, \Swift_Mailer $mailer)
{
$this->twig = $twig;
$this->mailer = $mailer;
}
public function onContractCreated(ContractEvent $event)
{
$contract = $event->getContract();
$body = $this->renderTemplate($contract);
$projectManager = $contract->getProjectManager();
$message = \Swift_Message::newInstance()
->setSubject('Contract ' . $contract->getId() . ' created')
->setFrom('noreply#example.com')
->setTo('dev#example.com')
->setBody($body)
;
$this->mailer->send($message);
}
public function renderTemplate($contract)
{
return $this->twig->render(
'AcmeContractBundle:Contract:mailer.html.twig',
array(
'contract' => $contract
)
);
}
}

Mocking DB/SQL fat free framework (F3) phpunit

I am trying to write a test for a function which returns false or object.
class Environment {
protected $db , $env, $envMapper= "";
public function __construct($dbConnection) {
$this->db = $dbConnection;
$this->setMapper($this->db);
}
public function setMapper($db){
$this->envMapper=new DB\SQL\Mapper($this->db,'environment');
}
public function save($envName) {
$this->envMapper->name = $envName;
return $this->envMapper->save();
}
/**
* #param $envId
*/
public function get($envId) {
}
/***
* #param $envName
*/
public function getByName($envName) {
}
}
Tests:
class EnvironmentTest extends PHPUnit_Framework_TestCase {
protected $db = "";
public function setup()
{
$this->db = $this->getMockBuilder('SqlHelper')
->setMethods(array('connect'))
->getMock();
}
public function testSave() {
$object = new StdClass();
$env = new Environment($this->db);
$this->assertEquals($object, $env->save('Test'));
}
}
I am not sure how should I change so that it would be testable, it always return
EnvironmentTest::testSave
PHPUnit_Framework_MockObject_RuntimeException: You cannot serialize or
unserialize PDO instances

Symfony2 , Container Service

Hello i have an error on EventSubscriber for form in sonata admin
namespace OneA\AdvertBundle\Form\EventListener;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\DependencyInjection\ContainerAware;
class CategoryFieldsSubscriber extends ContainerAware implements EventSubscriberInterface
{
private $factory;
public function __construct(FormFactoryInterface $factory)
{
$this->factory = $factory;
}
public static function getSubscribedEvents()
{
return array(FormEvents::PRE_SET_DATA => 'preSetData');
}
public function preSetData(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
//$form->add('advert_fields', 'text');
$advert_type = $form->get('advert_type')->getData();
$this->getFields($form, $advert_type);
}
public function getFields($form, $advert_type)
{
$form->add('advert_fields', 'text', array(
'label' => 'dfjg',
));
$this->container->get('one_a_advert.admin_motors_field')->getFieldsForm($form);
}
}
When i call the container i have this error
FatalErrorException: Error: Call to a member function get() on a non-object in
To the container->get(
You need to send in your constructor required container like this:
services:
kernel.listener.your_listener:
class: OneA\AdvertBundle\Form\EventListener\CategoryFieldsSubscriber
arguments: [#factory, #service_container]
and use this like
private $container;
private $factory;
public function __construct(FormFactoryInterface $factory, $container)
{
$this->container = $container;
$this->factory = $factory;
}

Resources