Buy
Buy

Mad Test Debugging

When we mess up in a web app, we see Symfony's giant exception page. I want that same experience when I'm building an API.

At the root of the project there's a resources/ directory with an ApiTestCase.php file. This has all the same stuff as our ApiTestCase plus some pretty sweet new debugging stuff.

Copy this and paste it over our class.

First, check out onNotSuccessfulTest():

... lines 1 - 64
protected function onNotSuccessfulTest(Exception $e)
{
if (self::$history && $lastResponse = self::$history->getLastResponse()) {
$this->printDebug('');
$this->printDebug('<error>Failure!</error> when making the following request:');
$this->printLastRequestUrl();
$this->printDebug('');
$this->debugResponse($lastResponse);
}
throw $e;
}
... lines 78 - 205

If you have a method with this name, PHPUnit calls it whenever a test fails. I'm using it to print out the last response so we can see what just happened.

I also added a few other nice things, like printLastRequestUrl().

... lines 1 - 90
protected function printLastRequestUrl()
{
$lastRequest = self::$history->getLastRequest();
if ($lastRequest) {
$this->printDebug(sprintf('<comment>%s</comment>: <info>%s</info>', $lastRequest->getMethod(), $lastRequest->getUrl()));
} else {
$this->printDebug('No request was made.');
}
}
... lines 101 - 200

Next up is debugResponse() use it if you want to see what a Response looks like:

... lines 1 - 101
protected function debugResponse(ResponseInterface $response)
{
$this->printDebug(AbstractMessage::getStartLineAndHeaders($response));
$body = (string) $response->getBody();
... lines 106 - 172
}
... lines 174 - 200

This crazy function is something I wrote - it knows what Symfony's error page looks like and tries to extract the important parts... so you don't have to stare at a giant HTML page in your terminal. I hate that. It's probably not perfect - and if you find an improvement and want to share it, you'll be my best friend.

And finally, whenever this class prints something, it's calling printDebug(). And right now, it's about as dull as you can get:

... lines 1 - 179
protected function printDebug($string)
{
echo $string."\n";
}
... lines 184 - 200

I think we can make that way cooler. But first, with this in place, it should print out the last response so we can see the error:

php bin/phpunit -c app src/AppBundle/Tests/Controller/Api/ProgrammerControllerTest.php

Ah hah!

Catchable Fatal Error: Argument 1 passed to Programmer::setUser() must
be an instance of AppBundle\Entity\User, null given in ProgrammerController.php
on line 29.

So the problem is that when we delete our database, we're also deleting our hacked-in weaverryan user:

... lines 1 - 17
public function newAction(Request $request)
{
... lines 20 - 23
$programmer->setUser($this->findUserByUsername('weaverryan'));
... lines 25 - 30
}
... lines 32 - 33

Let's deal with that in a second - and do something cool first. So, remember how some of the app/console commands have really pretty colored text when they print? Well, we're not inside a console command in PHPUnit, but I'd love to be able to print out with colors.

Good news! It turns out, this is really easy. The class that handles the styling is called ConsoleOutput, and you can use it directly from anywhere.

Start by adding a private $output property that we'll use to avoid creating a bunch of these objects. Then down in printDebug(), say if ($this->output === null) then $this->output = new ConsoleOutput();. This is the $output variable you're passed in a normal Symfony command. This means we can say $this->output->writeln() and pass it the $string:

... lines 1 - 12
use Symfony\Component\Console\Output\ConsoleOutput;
... lines 14 - 15
class ApiTestCase extends KernelTestCase
{
... lines 18 - 29
/**
* @var ConsoleOutput
*/
private $output;
... lines 34 - 184
protected function printDebug($string)
{
if ($this->output === null) {
$this->output = new ConsoleOutput();
}
$this->output->writeln($string);
}
... lines 193 - 207
}

I'm coloring some things already, so let's see this beautiful art! Re-run the test:

php bin/phpunit -c app src/AppBundle/Tests/Controller/Api/ProgrammerControllerTest.php

Hey! That error is hard to miss!

Seeing the Exception Stacktrace!

Ok, one more debugging trick. What if we really need to see the full stacktrace? The response headers are printed on top - and one of those actually holds the profiler URL for this request. And to be even nicer, my debug code is printing that at the bottom too.

Pop that into the browser. This is the profiler for that API request. It has cool stuff like the database queries, but most importantly, there's an Exception tab - you can see the full, beautiful exception with stacktrace. This is huge.

Leave a comment!

  • 2019-01-30 Diaconescu Petrisor

    As soon as my eyes landed on my test code maked perfect sense. That was a very infurating mistake. I was so entranched in APITest code that I saw nothing else.
    Thank you. It works now, indeed

  • 2019-01-29 weaverryan

    Hi again Diaconescu Petrisor!

    Sorry for being slow! I've just cloned your code and got it working - you already did all the hard work and were very close! Here is the PR: https://github.com/petre-sy...

    I really only needed to do 2 things:

    1) In the test function, you were instantiating your own Client object. You need to use $this->client instead. Otherwise, the static history property will never be populated in ApiTestCase and so we don't have access to the Response to print it.

    2) Once I did this, onNotSuccessfulTest was successfully being called and the $lastResponse variable was set. But THEN I got an error that the symfony/css-selector is not installed. Indeed, inside the debugResponse function, we're using some code with the $crawler that needs the symfony/css-selector to be installed. Once I did that, it all worked!

    Let me know if this makes sense!

    Cheers!

  • 2019-01-28 Diaconescu Petrisor

    I added two new commits.
    I have only the failing normal message that phpunit normally give. I don't see which line in ProgrammerController is the one that makes the code to explode. In other words i don't see anything that's scrapped from 500 symfony error page.

  • 2019-01-24 Diaconescu Petrisor

    I added recently two new commits because I added the new panther browser test to the mix.
    I don't see anything at all. Is just the normal failing test message. like this:
    Testing Project Test Suite
    array(0) {
    }
    F 1 / 1 (100%)

    Time: 2.33 seconds, Memory: 30.00MB

    There was 1 failure:

    1) App\Tests\Controller\Api\ProgrammerControllerTest::testPOST
    Failed asserting that 500 matches expected 201.

    /home/petrero/www/Symfony/RestAPISite/tests/Controller/Api/ProgrammerControllerTest.php:27

    There's no trace of 500 error page here. Indeed in console where run panther browser appear the reason respectivelly: Uncaught PHP Exception Doctrine\DBAL\Exception\NotNullConstraintViolationException: "An exception occurred while executing 'INSERT INTO programmer (nickname, avatar_number, tag_line, power_level, user_id) VALUES (?, ?, ?, ?, ?)' with params ["ObjectOrienter", 5, "

  • 2019-01-23 weaverryan

    Hi Diaconescu Petrisor!

    Ah, I think I misunderstood you! Apologies! I thought you were telling me that you DID successfully "update" the code in that GitHub repository for the new exception page format. But, it sounds like that is not true. With your modified code, you are still not seeing the errors correctly in your terminal, is that correct? Do you see anything at all? Or still just an error? I can definitely look into helping :).

    Cheers!

  • 2019-01-23 Diaconescu Petrisor

    Do you see any fix to correct the problem that this code has?

  • 2019-01-22 weaverryan

    Hey Diaconescu Petrisor!

    Ah, it makes perfect sense! Nice work - and thanks for doing that :). I CAN see the repo - hopefully it will help other people. I see that most of the fixes were on this commit: https://github.com/petre-sy...

    Cheers!

  • 2019-01-16 Diaconescu Petrisor

    Cheers!
    I think I resolved debugResponse() method. I raised the same kind error on web interface and I hack the markup I found there. To raise this error I replace $programmer->setUser($this->getUser()) in new ProgrammerControoler method with $programmer->setUser('nnn') and I inspected the markup to see how it looks like.
    You may see the actual code at https://github.com/petre-sy.... Dwnload the zip archive from there.
    I tried to describe precisely in the last five commits what I reused from your code and what I replaced and also a little debugging. I hope is nothing ambiguous now.
    Thank you.

    Did you find the repo? You can download the code?

  • 2019-01-16 Victor Bocharsky

    Hey Diaconescu,


    > I did some debuggings. OnNotSuccessfulTest() is surely hit

    That's great, it means it should work.


    After I put debug statement in getLastResponse() method:
    var_dump(self::$history)die() as the first line of it and I see that this static variable is never populated because this line prints:
    array(0) {
    }

    Hm, it might depend on what test you're running. Because you added "die;" statement - it means you run only first failed test. You can try without "die;", probably further tests will populate self::$history property, but it also depends on do you send any requests or no in tests. If no - I think it makes sense that it's empty. Or try to use "--filter" option to execute exactly the test that sends requests.

    Btw, what version of PHPUnit do you use?

    Hm, btw, it's a little known fact, but your .env.local file does not read in test environment as far as I know, see config/bootstrap.php file for more context. It means, that you need to have another one for test env that's called .env.test.local. But if you only change APP_ENV=test in your .env.local - it should be not important as far as you have APP_ENV is set in your phpunit.xml.dist:


    <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nonamespaceschemalocation="http://schema.phpunit.de/6.5/phpunit.xsd" backupglobals="false" colors="true" bootstrap="config/bootstrap.php">
    <php>
    <ini name="error_reporting" value="-1"/>
    <env name="APP_ENV" value="test"/>
    <env name="SYMFONY_DEPRECATIONS_HELPER" value="weak"/>
    </php>



    </phpunit>

    Also, double check you have colors="true" in your phpunit.xml.dist.

    Cheers!

  • 2019-01-14 weaverryan

    Hey Diaconescu Petrisor!

    Yes, I think I may be understand you :). Specifically the problems are:

    > onNoSuccessfulTest method must be changed to match the signature of the new onNoSuccessfulTest phpunit method,

    and

    > the behaviour from these video debugResponse method must be changed because 500 error page is not the same as before

    I can't confirm that you're 100% correct about these, but they both make sense :). If you're able to push your example code, that *would* indeed help us. Also, have you been able to change the debugResponse() method to work with the new markup? Or are you having some issues with that?

    Cheers!

  • 2019-01-12 Diaconescu Petrisor

    I did some debuggings. OnNotSuccessful test is surely hit.
    After I put debug statement in getLastResponse method:
    var_dump(self::$history)die() as the first line of it and I see that this static variable is never populated because this line prints:
    array(0) {
    }
    This is the reason why if statement never executes.
    The only culprit I may think is phpunit settings, but I can't come up with the correct ones.
    As may I see setUBeforeClass is responsible to populate history static variable.
    So t looks like this:
    public static function setUpBeforeClass(){
    $handler = HandlerStack::create();

    $handler->push(Middleware::history(self::$history));

    self::$staticClient = new Client([
    'base_uri' => 'http://localhost:8000',
    'http_errors' => false,
    'handler' => $handler
    ]);

    self::bootKernel();
    }
    Configuration in phpunit.xml.dist is the standard one:

    <phpunit xmlns:xsi="http://www.w3.org/2001/XMLS..." xsi:nonamespaceschemalocation="http://schema.phpunit.de/6...." backupglobals="false" colors="true" bootstrap="config/bootstrap.php">
    <php>
    <ini name="error_reporting" value="-1"/>
    <env name="APP_ENV" value="test"/>
    <env name="SHELL_VERBOSITY" value="-1"/>
    </php>

    <testsuites>
    <testsuite name="Project Test Suite">
    <directory>tests</directory>
    </testsuite>
    </testsuites>

    <filter>
    <whitelist>
    <directory>src</directory>
    </whitelist>
    </filter>

    <listeners>
    <listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"/>
    </listeners>
    </phpunit>

    I use Symfony 4.2 right now so I created .env.local file where I put APP_ENV=test
    And I filled in env.test DATABASE_URL=mysql://root:mysql@127.0.0.1:3306/RestApiSiteTest

  • 2019-01-08 Diaconescu Petrisor

    Ok, I wasn't clear enough.
    In your screencast after ProgrammerControllerTest extends ApiTestCase when some phpunit test fails in console appear the actual reason of this failure. In your example this was 'Catchable Fatal Error: Argument 1 passed to Programmer::setUser() must
    be an instance of AppBundle\Entity\User, null given in ProgrammerController.php
    on line 29.'
    In my case if I run: 'APP_ENV=test bin/phpunit src/Tests/Controller/API/ProgrammerControllerTest.php' i only see that respective test fails:
    1) App\Tests\Controller\API\ProgrammerControllerTest::testPOST
    Failed asserting that 404 matches expected 201.
    I don't see the reason in phpunit console.
    I'am wrong If i say that the html part that is hacked into the console in your video are fragments from the 500 error page raised by Symfony when something wrong happen? If that is the case not only onNoSuccessfulTest method must be changed to match the signature of the new onNoSuccessfulTest phpunit method, but in case of Symfony4 to match the behaviour from these video debugResponse method must be changed because 500 error page is not the same as before. I triggered the same exception on web part and I inspected the 500 html page that was raised The methods that i write in previous asking is intending to extract only I considered to be the important part.
    Obviously something eluded me because on API side in phpunit cosole I see only that ProgrammerControllerTest::testPOST method fails. That's not an eror. But I don't see the reason of this failure in console.
    Where I am wrong?
    The actual code would be more helpfull? I have a git repository with all steps that i made in cronological order from the creation of the entities with bin/console make to changes I made in controllers and forms and so on
    testPOST method give the correct message failure, there's no errors, only the failure message, so it works with modifications i specified, but is not helpful enough because doesn't have any explanatory lines like in your video.
    I hope you excuse me. I don't want to torment you.
    Cheers and Happy new year

  • 2019-01-08 Victor Bocharsky

    Hey Diaconescu,

    Your questions difficult to track because you asked them in different comments and even in threads :)

    This looks good to me at the first sight. Hm, are you sure it is not printed? Because sometimes it might be printed in colors that difficult to spot in your terminal. Also, are you sure you get to this onNotSuccessfulTest() method during the execution? And are you sure you get exactly into that if statement? Try to debug it first using "die" statement like:


    protected function onNotSuccessfulTest(Throwable $t){
    die('DEBUG onNotSuccessfulTest');
    if ($lastResponse = $this->getLastResponse()) {
    die('DEBUG if');
    $this->printDebug('');
    $this->printDebug('<error>Failure!</error> when making the following request:');
    $this->printLastRequestUrl();
    $this->printDebug('');

    $this->debugResponse($lastResponse);
    }

    throw $t;
    }

    If you get the first die, comment it out and check if you see the second. This way you can find the problem and probably add more debug statements to better understand why. Also, it would be cool if you your terminal have search. If not, you can copy/paste the whole terminal output somewhere in a text editor and search for "DEBUG" keyword there.

    Cheers!

  • 2019-01-08 Victor Bocharsky

    This looks like a duplicate of this comment: https://symfonycasts.com/sc... - follow the thread there.

    Cheers!

  • 2019-01-08 Victor Bocharsky

    Hey Diaconescu,

    Wait, you don't see the errors of Symfony Flex? Or you don't see errors of PHPUnit? Because Symfony Flex does not relate to the error you mentioned like "Argument 1 passed to App\Entity\Programmer::setUser() must be an instance of App\Entity\User or null, string given, called in...".

    Could you tell me if the tests work and pass before you made your changes?

    Cheers!

  • 2019-01-07 Diaconescu Petrisor

    I tried to modify debugResponse method like so:


    protected function debugResponse(ResponseInterface $response){
    foreach ($response->getHeaders() as $name => $values) {
    $this->printDebug(sprintf('%s: %s', $name, implode(', ', $values)));
    }
    $body = (string) $response->getBody();

    $contentType = $response->getHeader('Content-Type');
    $contentType = $contentType[0];
    if ($contentType == 'application/json' || strpos($contentType, '+json') !== false) {
    $data = json_decode($body);
    if ($data === null) {
    // invalid JSON!
    $this->printDebug($body);
    } else {
    // valid JSON, print it pretty
    $this->printDebug(json_encode($data, JSON_PRETTY_PRINT));
    }
    } else {
    // the response is HTML - see if we should print all of it or some of it
    $isValidHtml = strpos($body, '</body>') !== false;

    if ($isValidHtml) {
    $this->printDebug('');
    $crawler = new Crawler($body);

    // very specific to Symfony's error page
    $isError = $crawler->filter('.trace-line ')->count() > 0
    || strpos($body, 'Symfony Exception') !== false;
    if ($isError) {
    $this->printDebug('There was an Error!!!!');
    $this->printDebug('');
    } else {
    $this->printDebug('HTML Summary (h1 and h2):');
    }

    foreach ($crawler->filter('.exception-message-wrapper h1')->extract(array('_text')) as $text) {
    $text = $this->removeLineBreaks($text);
    if ($isError) {
    $this->printErrorBlock($text);
    } else {
    $this->printDebug($text);
    }
    }
    foreach ($crawler
    ->filter('.trace-line')
    ->first()
    ->extract(array('_text')) as $text
    ){
    $text = $this->removeLineBreaks($text);
    if ($isError) {
    $this->printErrorBlock($text);
    } else {
    $this->printDebug($text);
    }
    }

    /*
    * When using the test environment, the profiler is not active
    * for performance. To help debug, turn it on temporarily in
    * the config_test.yml file (framework.profiler.collect)
    */
    $profilerUrl = $response->getHeader('X-Debug-Token-Link');
    if ($profilerUrl) {
    $fullProfilerUrl = $response->getHeader('Host')[0].$profilerUrl[0];
    $this->printDebug('');
    $this->printDebug(sprintf(
    'Profiler URL: <comment>%s</comment>',
    $fullProfilerUrl
    ));
    }

    // an extra line for spacing
    $this->printDebug('');
    } else {
    $this->printDebug($body);
    }
    }
    }

    and onNotSuccessfulTest like so:


    protected function onNotSuccessfulTest(Throwable $t){
    if ($lastResponse = $this->getLastResponse()) {
    $this->printDebug('');
    $this->printDebug('<error>Failure!</error> when making the following request:');
    $this->printLastRequestUrl();
    $this->printDebug('');

    $this->debugResponse($lastResponse);
    }

    throw $t;
    }

    And I created function


    protected function removeLineBreaks($text){
    // remove line breaks so the message looks nice
    $text = str_replace("\n", ' ', trim($text));
    // trim any excess whitespace "foo bar" => "foo bar"
    $text = preg_replace('/(\s)+/', ' ', $text);

    return $text;
    }

    Probably I misjudge something but i don't see the errors that Symfony Flex raise like 'Argument 1 passed to App\Entity\Programmer::setUser() must be an instance of App\Entity\User or null, string given, called in ...'
    in console when I run: APP_ENV=test bin/phpunit src/Tests/Controller/API/ProgrammerControllerTest.php

    The fragments of the page I want to see in console is not like the page that I see in web browser when in WebBrowser/ProgrammerController in new method instead of $programmer->setUser($this->getUser()); i
    put $programmer->setUser('nn') and submit the form ?

    Can I print in console ResponseInterface $response argument in debugResponse method? Is there some configuration I must made in Flex to make happen what is seen in this video?

  • 2019-01-05 Diaconescu Petrisor

    I tried to modify debugResponse method like so:
    protected function debugResponse(ResponseInterface $response){
    foreach ($response->getHeaders() as $name => $values) {
    $this->printDebug(sprintf('%s: %s', $name, implode(', ', $values)));
    }
    $body = (string) $response->getBody();

    $contentType = $response->getHeader('Content-Type');
    $contentType = $contentType[0];
    if ($contentType == 'application/json' || strpos($contentType, '+json') !== false) {
    $data = json_decode($body);
    if ($data === null) {
    // invalid JSON!
    $this->printDebug($body);
    } else {
    // valid JSON, print it pretty
    $this->printDebug(json_encode($data, JSON_PRETTY_PRINT));
    }
    } else {
    // the response is HTML - see if we should print all of it or some of it
    $isValidHtml = strpos($body, '</body>') !== false;

    if ($isValidHtml) {
    $this->printDebug('');
    $crawler = new Crawler($body);

    // very specific to Symfony's error page
    $isError = $crawler->filter('.trace-line ')->count() > 0
    || strpos($body, 'Symfony Exception') !== false;
    if ($isError) {
    $this->printDebug('There was an Error!!!!');
    $this->printDebug('');
    } else {
    $this->printDebug('HTML Summary (h1 and h2):');
    }

    foreach ($crawler->filter('.exception-message-wrapper h1')->extract(array('_text')) as $text) {
    $text = $this->removeLineBreaks($text);
    if ($isError) {
    $this->printErrorBlock($text);
    } else {
    $this->printDebug($text);
    }
    }
    foreach ($crawler
    ->filter('.trace-line')
    ->first()
    ->extract(array('_text')) as $text
    ){
    $text = $this->removeLineBreaks($text);
    if ($isError) {
    $this->printErrorBlock($text);
    } else {
    $this->printDebug($text);
    }
    }

    /*
    * When using the test environment, the profiler is not active
    * for performance. To help debug, turn it on temporarily in
    * the config_test.yml file (framework.profiler.collect)
    */
    $profilerUrl = $response->getHeader('X-Debug-Token-Link');
    if ($profilerUrl) {
    $fullProfilerUrl = $response->getHeader('Host')[0].$profilerUrl[0];
    $this->printDebug('');
    $this->printDebug(sprintf(
    'Profiler URL: <comment>%s</comment>',
    $fullProfilerUrl
    ));
    }

    // an extra line for spacing
    $this->printDebug('');
    } else {
    $this->printDebug($body);
    }
    }
    }

    and onNotSuccessfulTest like so: protected function onNotSuccessfulTest(Throwable $t){
    if ($lastResponse = $this->getLastResponse()) {
    $this->printDebug('');
    $this->printDebug('<error>Failure!</error> when making the following request:');
    $this->printLastRequestUrl();
    $this->printDebug('');

    $this->debugResponse($lastResponse);
    }

    throw $t;
    }

    And I created function
    protected function removeLineBreaks($text){
    // remove line breaks so the message looks nice
    $text = str_replace("\n", ' ', trim($text));
    // trim any excess whitespace "foo bar" => "foo bar"
    $text = preg_replace('/(\s)+/', ' ', $text);

    return $text;
    }

    Probably I misjudge something but i don't see the errors that Symfony Flex raise like 'Argument 1 passed to App\Entity\Programmer::setUser() must be an instance of App\Entity\User or null, string given, called in ...'
    in console when I run: APP_ENV=test bin/phpunit src/Tests/Controller/API/ProgrammerControllerTest.php

    The fragments of the page I want to see in console is not like the page that I see in web browser when in WebBrowser/ProgrammerController in new method instead of $programmer->setUser($this->getUser()); i
    put $programmer->setUser('nn') and submit the form ?

    Can I print in console ResponseInterface $response argument in debugResponse method? Is there some configuration I must made in Flex to make happen what is seen in this video?

  • 2019-01-05 Diaconescu Petrisor

    Before I asked I had tried this:


    protected function onNotSuccessfulTest(Throwable $t){
    if ($lastResponse = $this->getLastResponse()) {
    $this->printDebug('');
    $this->printDebug('<error>Failure!</error> when making the following request:');
    $this->printLastRequestUrl();
    $this->printDebug('');

    $this->debugResponse($lastResponse);
    }


    throw $t;
    }

    But the stack trace is nowhere to be seen

  • 2019-01-04 Victor Bocharsky

    Hey Diaconescu,

    It's an easy fix! As you can see from the error message, the onNotSuccessfulTest() method is not compatible with one from the newer version - that was a BC break from PHPUnit. So the fix: just change ours ApiTestCase::onNotSuccessfulTest(\Exception $e) signature to ApiTestCase::onNotSuccessfulTest(\Throwable $t), i.e. allow a Throwable object to be passed there. And that's it :)

    Cheers!

  • 2019-01-04 Diaconescu Petrisor

    I ry to rework this tutorial with Symfony 4, Flex, php7.2, phpunit 6.5. I tried yor code from episode 4 but phpunit raise the error "Declaration of App\Tests\ApiTestCase::onNotSuccessfulTest(Exception $e) should be compatible with PHPUnit\Framework\TestCase::onNotSuccessfulTest(Throwable $t)"
    How must look ApiTestCase to get the Symfony exception page using Throwable instead of exceptions?

  • 2018-07-18 Diego Aguiar

    Hey Coder

    You can find those debugging methods inside src/AppBundle/Test/ApiTestCase.php

    Cheers!

  • 2018-07-18 Coder

    where can we get that function which extract info from error with html ?

  • 2018-06-11 Victor Bocharsky

    Hey Shaun,

    First of all, try to clear the cache. Also, make sure you use the correct namespace of the Route, it should be:

    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;

    And try to debug a bit with "bin/console debug:router", do you see this route in the list?

    Cheers!

  • 2018-06-08 Shaun

    Thanks Victor Bocharsky

    The issue I am now having is that because I am using Symfony 4, the route for the API is not being picked up and I am getting following error:

    HTML Summary (h1 and h2):
    Symfony Exception
    ResourceNotFoundException NotFoundHttpException
    HTTP 404 Not Found
    No route found for "POST /app_test.php/api/programmers"

  • 2018-06-08 Victor Bocharsky

    Hey Shaun,

    The message is clear enough - method's signature was changed, so you need to change "onNotSuccessfulTest(Exception $e)" to "onNotSuccessfulTest(Throwable $t)" as in parent class.

    About the second problem, try to sync vendor/ directory, i.e. right click on vendor/ dir and select "Synchronize 'vendor'". If it does not help, try to re-execute "composer install" or remove vendor/ dir manually and re-run "composer install" again.

    Cheers!

  • 2018-06-07 Shaun

    I downloaded the ApiTestCase from episode 4 as I am using Guzzle veriosn 6, however when I run PHPUnit test I get the following error:

    Fatal error: Uncaught Declaration of AppBundle\Test\ApiTestCase::onNotSuccessfulTest(Exception $e) should be compatible with PHPUnit\Framework\TestCase::onNotSuccessfulTest(Throwable $t)

    And I am also getting the angry errors from PHPStorm regarding the Guzzle paths ;)

    use GuzzleHttp\Message\AbstractMessage;
    use GuzzleHttp\Message\ResponseInterface;
    use GuzzleHttp\Subscriber\History;

  • 2018-02-13 weaverryan

    Hey Nacer!

    Ah yes. So, this tutorial uses version *5* of Guzzle. But, before episode 4 (https://knpuniversity.com/s..., we upgraded to Guzzle 6. If you download the start code for that tutorial, you'll find an ApiTestCase that works with version 6 :).

    Cheers!

  • 2018-02-13 Nacer

    I'm on GuzzleHttp 6, I' think the file in resources need to be updated

  • 2018-02-12 Victor Bocharsky

    Hey Nacer,

    What do you mean? Can't PhpStorm find these classes or these classes just are not used in the class? If the 2nd, i.e. you don't use those classes - just remove the namespaces. But if the first one - please, make sure you've installed dependencies with "composer install". Also, what version of Guzzle do you use? Probably you use a different major version, so those namespaces were changed and you need to use the new ones.

    Cheers!

  • 2018-02-11 Nacer

    Hi all, my Phpstrom don't like these lines in ApiTestCase calss

    use GuzzleHttp\Message\AbstractMessage;
    use GuzzleHttp\Message\ResponseInterface;
    use GuzzleHttp\Subscriber\History;

  • 2016-12-19 weaverryan

    Hey emm!

    Haha, for the purposes of learning the REST stuff, I would probably not bother upgrading. However, we actually *do* upgrade to Symfony 3 and Guzzle 6 between episode 3 and 4... so episode 4 has all the latest stuff (if you download its course code): http://knpuniversity.com/sc.... So, if you want, that should make upgrading your ApiTestCase to Guzzle 6 pretty easy :).

    Cheers!

  • 2016-12-19 emm

    Hi there!! So.. when i use guzzlehttp/guzzle v6.* the code of resource/ApiTesterCase(from the start directory) makes phpStorm angry :P. i read some documentation as of the upgrades of guzzlehttp v5 and v6 but instead of fixing/changing the code i just downgraded the package to v 5. Should i bother fixing the changes to the current version for now? I'm not sure if this is a real or rehtorical question..

    thanks in advance.

  • 2016-08-01 weaverryan

    Hi there!

    Yea, great question! This is a personal preference of mine. The reason is that Guzzle is the standard in the PHP world for making HTTP/API requests. Symfony's client/crawler is quite good, but the crawler (specifically) is useful for crawling HTML pages - it doesn't serve you any purpose when making API requests. So, I usually think it makes more sense to use Guzzle, since you'll probably also use it in the real-world to make API requests to other services.

    However, there is one advantage that Symfony's client has over Guzzle. Because (with the Symfony client) you are *not* making real HTTP requests (you are making "fake" requests into Symfony's kernel), you can potentially do 2 interesting things. First, you could change some setting in the container right in your test class, make the request class, and your code will use that setting. Second, and probably more interesting, you can turn on the profiler and get information from the profiler (e.g. "was an email sent?"). That's not enough for me to want to use it however :).

    Thanks for the question - hope that clarifies!

    Cheers!

  • 2016-07-30 Lipiluk

    I would like to ask, why are you using Guzzle instead of in-built Symfony's client/crawler? Are there any advantages or disadvantages of using those both? As far as I can see Symfony's offer programmers such an ability. Thank you for any reply.