I'm writing my firsts tests with Symfony 4.1, and I'm experiencing an odd problem. The test is to make sure the endpoint returns status 200:
public function testFetchTaskEndpointStatusCode200()
{
$client = static::createClient();
$client->request("GET", "/tasks");
$this->assertEquals(200, $client->getResponse()->getStatusCode());
}
The endpoint then triggers the following method:
/**
* #Route("/tasks")
* #Method("GET")
*/
public function fetchAction()
{
$repository = $this->getDoctrine()->getRepository(Task::class);
$tasks = $repository->findAll();
return $this->json([
'tasks' => $tasks
]);
}
Using Insomnia software and through browser, I can see the returned status is 200, but when executing the test:
Failed asserting that 500 matches expected 200.
Why?
At testing time some error occurs on your server side code, hence the error code 500. Since we cannot see your testcase and setup it will be hard for us to guide you
Adding
<phpunit>
...
<!-- define your env variables for the test env here -->
<env name="DATABASE_URL" value="mysql://username:password#127.0.0.1:3306/database" />
</phpunit>
to phpunit.xml.dist solved it.
Related
I'm having trouble with periodic tasks on ElasticBeanstalk Worker Tier with Symfony app.
I have deployed the same source code on App Server and Worker Tier.
I have setup my cron.yaml file and it is successfully loaded.
Messages are sent but I get a 406 error :
"POST /worker/reclamation/auto-reply HTTP/1.1" 406 481 "-" "aws-sqsd/2.4"
My cron.yaml file:
version: 1
cron:
- name: "reclamation-reply"
url: "/worker/reclamation/auto-reply"
schedule: "*/10 * * * *"
AWS Documentation says :
The URL is the path to which the POST request is sent to trigger the
job.
From there, I decided to code a FOSRest Route with POST Method in which I trigger the command I need to run.
I don't know if is the right way to do it, so, I suppose my problem may come from here.
/**
* #FOSRest\Route("/worker")
*/
class WorkerController extends AbstractController
{
/**
* #FOSRest\Post("/reclamation/auto-reply")
*/
public function ticketReply(KernelInterface $kernel)
{
$application = new Application($kernel);
$application->setAutoExit(false);
$input = new ArrayInput(array(
'command' => 'app:reclamation:reply',
));
$output = new NullOutput();
$application->run($input, $output);
return new Response("");
}
Thank you in advance for your help !
It finally works !
It seems the error occured because I forget to configure the format_listener of my FOSRest Route.
My app starts locally by http : //sm1/app/web/app_dev.php (symfony3).
PHPUnit test has been build by framework.
namespace Tests\AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class GoodControllerTest extends WebTestCase
{
public function testCompleteScenario()
{
// Create a new client to browse the application
$client = static::createClient([], ['HTTP_HOST' => 'sm1']);
// Create a new entry in the database
$crawler = $client->request('GET', '/good/');
$this->assertEquals(200,
$client->getResponse()->getStatusCode(),
"Unexpected HTTP status code for GET /good/"
);
$crawler = $client->click(
$crawler->selectLink('Create a new entry')->link());
But after test running I've got an error
There was 1 error:
1) Tests\AppBundle\Controller\GoodControllerTest::testCompleteScenario
InvalidArgumentException: The current node list is empty.
/home/sm1/www/app/vendor/symfony/symfony/src/Symfony/Component/DomCrawler/Crawler.php:735
/home/sm1/www/app/tests/AppBundle/Controller/GoodControllerTest.php:18
and in a log file this message:
request.INFO: Matched route "{route}".
{"route":"good_index","route_parameters":
{"_controller":"AppBundle\Controller\GoodController::indexAction",
"_route":"good_index"},
"request_uri":"http://sm1/good/","method":"GET"} []
How to fix "request_uri" from "http : //sm1/good/"
to "http : //sm1/app/web/app_dev.php/good/" ?
It is necessary to start web app only by http://app. That is, to use PHPUnit you need a virtual host. If the name of the input script is different from the default, note this in the file .htaccess.
use Symfony\Component\HttpFoundation\Session\Session;
...
public function __construct()
{
//echo ini_get('session.auto_start'); die;
$this->session = new Session();
/**
* #Route("/", name="registration_index")
* #Route("/user/registration", name="registration")
* #Method("GET")
*/
public function indexAction()
{
//$this->session->getFlashBag()->add('notice', 'Profile updated');
$errors = $this->session->getFlashBag()->get('notice', array());
print_r($errors);
return $this->render('registration.html.twig', ['errors' => $errors]);
}
/**
* #Route("/user/registration", name="post_registration")
* #Method("POST")
* #return mixed
*/
public function postAction()
{
//$this->session->getFlashBag()->add('errors', 'hahaha');
$this->session->getFlashBag()->add('notice', 'Profile updated');
return $this->redirectToRoute('registration');
}
I will want to display error messages near input fields if there is registration failure. Trying to use session flashdata.
When user goes to postAction method, he is redirected to indexAction. But
print_r($errors);
prints empty array. Why is that? Without redirect - it works ok.
This was not symfony problem, but php server problem. Even code examples from php manual without symfony did not work.
I was running server like this:
php -S 0.0.0.0:8000
and for some reasons the session did not work on it.
When I started using nginx server, session started working.
Is there a reason why you are not using symfony Forms to get this functionality? Symfony Forms are perfect for registration pages.
By the way, if you are doing this in a controller then you don't need the constructor method. Instead get the session from Request->getSession()
I confirm that WebCookie sais in his comment: In the controller please use $this->addFlash() if your need to add a flash message within a controller.
Notice you can also use session service like this: $this->get('session')->getFlashBag()->add()
For further informations Flash messages.
My understanding of kernel.terminate is that it triggers after the response has been returned to the client.
In my testing tough, this does not appear to be the case. If I put a sleep(10) in the function that's called on kernel.terminate. the browser also waits for 10 seconds. The processing seems to be happening before the response is sent.
I have the following in config:
calendar:
class: Acme\CalendarBundle\Service\CalendarService
arguments: [ #odm.document_manager, #logger, #security.context, #event_dispatcher ]
tags:
- { name: kernel.event_subscriber }
My subscriber class:
class CalendarService implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
'kernel.terminate' => 'onKernelTerminate'
);
}
public function onKernelTerminate()
{
sleep(10);
echo "hello";
}
}
UPDATE
This appears to be related to Symfony not sending a Content-Length header. If I generate that, the response return properly.
// app_dev.php
...
$kernel = new AppKernel('dev', true);
$kernel->loadClassCache();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
// --- START EDITS ---
$size = strlen($response->getContent());
$response->headers->set('Content-Length', $size);
$response->headers->set('Connection', 'close');
// ---- END EDITS ----
$response->send();
$kernel->terminate($request, $response);
This issue turned out to be very specific to my setup (Nginx, PHP-FCGI, Symfony).
There were a handful of issues in play that caused the issue:
Symfony does not include a Content-Length nor Connection: close header
PHP-FCGI does not support the fastcgi_finish_request function
Nginx buffers the response from PHP-FCGI because Gzip is on
The solution was to switch from PHP-FCGI to PHP-FPM in order to get support for fastcgi_finish_request. Symfony internally calls this before executing the kernel terminate logic thereby definitively closing the connection.
Another way to solve this would be to turn off Gzip on Nginx, but this wasn't really an option for me.
I make some functional test with Symfony 2 and phpunit.
But i've some trouble with a Service.
Let me explain.
During my run test, i want to use some service used by the application. So i juste set my setUp function for setting the kernel :
static::$kernel = static::createKernel();
static::$kernel->boot();
$this->objectFactory = static::$kernel->getContainer()->get('some.application.objectfactory');
So i've this and in my function i need to used a service that return an object so i call my service like that
$var = $this->objectFactory->getObject($id);
and obviously in my tearDown function i just :
protected function tearDown()
{
$this->client->restart();
unset($this->client, $this->objectFactory);
}
So my problem is when i run a test i've this message :
Symfony\Component\DependencyInjection\Exception\InactiveScopeException: You cannot create a service ("request") of an inactive scope ("request").
And i can't find a way to solve this.
Did someone have any idea ??
My version of Symfony is 2.2.1 and my version of phpunit is 3.7.19
If someone can help me, i could be very happy.
I'm sorry if my English isn't so good.
EDIT
Maybe it could help someone, in the service i used that : :
$request = $this->container->get('request');
It seems to be the reason why it dosen't work, when i remove it, it doesn't say the error, but they still doesn't work.
EDIT
#Cyprian
According to you have change my code for what i want.
So i just add to my service, in the function that i want, the client (Client web test case), and then inside the function i just add this :
if (isset($client)) {
$request = $client->getRequest();
} else {
$request = $this->container->get('request');
}
So in my function where i call the service i've just this :
public function getObject($id)
{
//Get the service from the kernel
$service = static::$kernel->getContainer()->get('service');
$object = $service->getObject($id, $this->client);
}
and it works fine like this
#nifr
Your idea doesn't work for me, but i think your idea wasn't wrong, they just not works in my case
However Thanks for your help, i'm happy i works now, and i expect that post could help someone else
Try get request from the client, not service container:
$request = $this->client->getRequest();
In that way you can also get kernel and/or container:
$kernel = $this->client->getKernel();
$container = $this->client->getContainer();
One more useful tip: kernel from the client is rebooted between each two requests. So, for example if you pass your mock to client's container and do some request, in next request (after the first one) the container will not contain your mock.
There is no request available in phpUnit as long as you don't construct one.
If you want to test a request. create it like this:
use Symfony\Component\HttpFoundation\Request;
protected $request;
public function setUp()
{
// ...
$this->request = new Request();
// ... modify your request acccording to your needs
}
and add/call a setter in your Service using the request.
$service = $this->kernel->getContainer()->get('your_service')
$service->setRequest($this->request);
or create a Functional Test with WebtestCase.