PHPUnit and Jenkins: Datetime expected and Datetime actual - datetime

I have the test class:
class ClassTest extends \PHPUnit_Framework_TestCase
{
/**
* #covers \Path\Class::method()
* #dataProvider methodData
*/
public function testMethod($data, $expected)
{
$this->object = $this->getMockBuilder("Path\Class")
->setConstructorArgs([..])
->getMock();
....
$response = $this->object->method($data);
$this->assertEquals($expected, $response);
}
public function methodData()
{
$entity= new Entity();
$entity->setDateArrivee(new \DateTime());
....
....
}
}
I run the PHPunit in Jenkins job. the datetime of dateArrivee in the response and the expected is not same. I don't know why.
Can you help me ?

I write this method in the testMethod
$entity->setDateArrivee(new \DateTime());

Related

How to use JMSSerializer with symfony 4.2

i am building an Api with symfony 4.2 and want to use jms-serializer to serialize my data in Json format, after installing it with
composer require jms/serializer-bundle
and when i try to use it this way :
``` demands = $demandRepo->findAll();
return $this->container->get('serializer')->serialize($demands,'json');```
it gives me this errur :
Service "serializer" not found, the container inside "App\Controller\DemandController" is a smaller service locator that only knows about the "doctrine", "http_kernel", "parameter_bag", "request_stack", "router" and "session" services. Try using dependency injection instead.
Finally i found the answer using the Symfony serializer
it's very easy:
first : istall symfony serialzer using the command:
composer require symfony/serializer
second : using the serializerInterface:
.....//
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
// .....
.... //
/**
* #Route("/demand", name="demand")
*/
public function index(SerializerInterface $serializer)
{
$demands = $this->getDoctrine()
->getRepository(Demand::class)
->findAll();
if($demands){
return new JsonResponse(
$serializer->serialize($demands, 'json'),
200,
[],
true
);
}else{
return '["message":"ooooops"]';
}
}
//......
and with it, i don't find any problems with dependencies or DateTime or other problems ;)
As I said in my comment, you could use the default serializer of Symfony and use it injecting it by the constructor.
//...
use Symfony\Component\Serializer\SerializerInterface;
//...
class whatever
{
private $serializer;
public function __constructor(SerializerInterface $serialzer)
{
$this->serializer = $serializer;
}
public function exampleFunction()
{
//...
$data = $this->serializer->serialize($demands, "json");
//...
}
}
Let's say that you have an entity called Foo.php that has id, name and description
And you would like to return only id, and name when consuming a particular API such as foo/summary/ in another situation need to return description as well foo/details
here's serializer is really helpful.
use JMS\Serializer\Annotation as Serializer;
/*
* #Serializer\ExclusionPolicy("all")
*/
class Foo {
/**
* #Serializer\Groups({"summary", "details"})
* #Serializer\Expose()
*/
private $id;
/**
* #Serializer\Groups({"summary"})
* #Serializer\Expose()
*/
private $title;
/**
* #Serializer\Groups({"details"})
* #Serializer\Expose()
*/
private $description;
}
let's use serializer to get data depends on the group
class FooController {
public function summary(Foo $foo, SerializerInterface $serialzer)
{
$context = SerializationContext::create()->setGroups('summary');
$data = $serialzer->serialize($foo, json, $context);
return new JsonResponse($data);
}
public function details(Foo $foo, SerializerInterface $serialzer)
{
$context = SerializationContext::create()->setGroups('details');
$data = $serialzer->serialize($foo, json, $context);
return new JsonResponse($data);
}
}

PhpUnit dataProviders vs Coverage

I decided, that it will be fine if I use data providers but when i try to generate code coverage whole tested class has 0% coverage.. Can someone tell me why?
Test class:
class AuthorDbManagerTest extends AbstractDbManagerTest
{
public function setUp()
{
parent::setUp();
}
/**
* #dataProvider instanceOfProvider
* #param bool $isInstanceOf
*/
public function testInstances(bool $isInstanceOf)
{
$this->assertTrue($isInstanceOf);
}
public function instanceOfProvider()
{
$manager = new AuthorDbManager($this->getEntityManagerMock());
return [
"create()" => [$manager->create() instanceof Author],
"save()" => [$manager->save(new Author()) instanceof AuthorDbManager],
"getRepository" => [$manager->getRepository() instanceof EntityRepository],
];
}
}
Tested class:
class AuthorDbManager implements ManagerInterface
{
protected $entityManager;
protected $repository;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
$this->repository = $entityManager->getRepository(Author::class);
}
public function create(array $data = [])
{
return new Author();
}
public function getRepository(): EntityRepository
{
return $this->repository;
}
public function save($object): ManagerInterface
{
$this->entityManager->persist($object);
$this->entityManager->flush();
return $this;
}
}
Why my code coverage is 0% on AuthorDbManager?
Screen
The data in the DataProvider is collected before the actual tests start - and there is nothing useful being tested within the testInstances() method.
If you passed the classname and expected class into testInstances($methodName, $expectedClass):
public function testInstances(callable $method, $expectedClass)
{
$this->assertInstanceOf($expectedClass, $method());
}
The dataprovider could return a callable, and the expected result:
"create()" => [[$manager,'create'], Author::class],
then you'd at least be running the code with in the actual test. You may also be better to just pass back a string methodname - 'create', and run that with a locally created $manager instance - $manager->$method() in the test.
In general, it's best to test something as specific as you can - not just letting it convert to a true/false condition.

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

Testion controler method in symfony (phpUnit)

i need some help i want to write a unit test about a controler method , i have searched for examples and tested a lot of method's but none of them has worked:
Here is my controller:
class ComputerController extends Controller
{
/**
* #Route("/list-computers.html", name="back_computer_list")
* #return RedirectResponse|Response
*/
function listComputerAction()
{
$ad = $this->get("ldap_service");
$computers = $ad->getAllComputer();
return $this->render('BackBundle:Computer:list.html.twig', array(
"computers" => $computers,
));
}
I have tried to test it with mock like this:
class ComputerController extends Controller
{
/**
* #var EngineInterface
*/
private $templating;
public function setTemplating($templating)
{
$this->templating = $templating;
}
and i have created a test method:
class ComputerControllerTest extends TestCase {
public function testlistComputerAction(){
$templating = $this->getMockBuilder('BackBundle\Controller\ComputerController')->getMock();
$computers = [1,2];
$templating->expects($this->once())
->method('render')
->with('BackBundle:Computer:list.html.twig', array(
"computers" => $computers))
->will($this->returnValue( $computers));
$controller = new ComputerController();
$controller->setTemplating($templating);
$this->assertEquals('success', $controller->listComputerAction());
}
When i start executing phpunit , i have this warning"Trying to configure method "render" which cannot be configured because it does not exist, has not been specified, is final, or is static"
I would be thankful if someone has an idea about this
I tried to Test a method in ldapService : Here is the method's of the service that i want to test
/**
* #return bool|resource
*/
public function getLdapBind()
{
if (!$this->ldapBind) {
if ($this->getLdapConnect()) {
$this->ldapBind = #ldap_bind($this->ldapConnect, $this->ldapUser, $this->ldapPass);
}
}
return $this->ldapBind;
}
/**
* #param $ldapUser
* #param $password
* #return bool
*/
function isAuthorized($ldapUser, $password)
{
$result = false;
if ($this->ldapConnect) {
$result = #ldap_bind($this->ldapConnect, $ldapUser, $password);
}
return $result;
}
Here is the test (using Mock):
<?php
namespace BackBundle\Tests\Service;
use PHPUnit\Framework\TestCase;
use BackBundle\Service\LdapService;
use PHPUnit_Framework_MockObject_InvocationMocker;
class LdapServiceTest extends TestCase {
public function testgetLdapConnect()
{
// $LdapService = new LdapService();
$ldapMock = $this->getMockBuilder( 'LdapService')->setMethods(['getLdapBind'])->disableOriginalConstructor()->getMock();
$ldapMock->expects($this->once())
// ->method()
->with(array('ldap_bind', 'mike', 'password'))
->will($this->returnValue(true));
$ldapMock->isAuthorized('mike', 'password');
}
}
But i have a warning that i can't resolve : "Method name matcher is not defined, cannot define parameter matcher without one"
If someone , has an idea about that please
Honestly, there is nothing useful to test in that three-line controller. #1 is the service container, and #3 is the Twig subsystem. Line #2 can be unit tested on it's own.
With more complex controllers, I have found that making them a service where all the dependencies are passed in, either by constructor, or into the action itself does make slightly more complex controllers quite easy, but very few need that anyway.

Too many connection during unit testing

I have a project with a lot of tests class like
class MyTest extends BaseTestCase
{
public function __construct()
{
parent::__construct();
$this->em = $this->get('doctrine')->getManager();
}
public function setUp() {
$this->init();
//load sql data for the tests
$path = $this->get('kernel')->locateResource('#Bundle/Data/Test.sql');
$content_file_sql_data = file_get_contents($path);
$stmt = $this->em->getConnection()->prepare($content_file_sql_data);
$stmt->execute();
$stmt->closeCursor();
}
/*
* Then we do a lot of tests using the database
*/
}
They all extends my BaseTestCase:
abstract class BaseTestCase extends \PHPUnit_Framework_TestCase {
protected $_container;
protected $kernel;
public function __construct() {
parent::__construct();
$this->kernel = new \AppKernel("test", true);
$this->kernel->boot();
$this->_container = $this->kernel->getContainer();
$this->init();
}
//empty the database before each test class
public function init() {
$this->_application = new Application($this->kernel);
$this->_application->setAutoExit(false);
//rebuild and empty the database
$this->runConsole("doctrine:schema:drop", array("--force" => true));
$this->runConsole("doctrine:schema:create");
}
Since I have a lot of tests, i have recently got some errors PDOException: SQLSTATE[08004] [1040] Too many connections. It's like phpunit never close database connection, and around 100 tests I get this error for all the other tests.
How can i fix it?
I tried to put a last test doing $this->em->close() at the end of each test class but it didn't solve it
Some additional information: i'm pretty sure I don't have an issue with ONE test, because if I change the order of the test suite, the error appears around the same amount of tests class passed
My solution was to override shutdown method in my Bundle class:
public function shutdown()
{
if ('test' == $this->container->getParameter('kernel.environment')) {
/* #var EntityManager $em */
$em = $this->container->get('doctrine.orm.default_entity_manager');
$em->getConnection()->close();
}
}

Resources