Chapters
39 Chapters
|
4:45:13
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!Compatible PHP versions: ^7.1.3, <8.0
Subscribe to download the code!Compatible PHP versions: ^7.1.3, <8.0
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
12.
Api Tests & Assertions
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
This tutorial works great for Symfony 5 and API Platform 2.5/2.6.
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": "^7.1.3, <8.0",
"ext-ctype": "*",
"ext-iconv": "*",
"api-platform/core": "^2.1", // v2.4.5
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/annotations": "^1.0", // 1.13.2
"doctrine/doctrine-bundle": "^1.6", // 1.11.2
"doctrine/doctrine-migrations-bundle": "^2.0", // v2.0.0
"doctrine/orm": "^2.4.5", // v2.7.2
"nelmio/cors-bundle": "^1.5", // 1.5.6
"nesbot/carbon": "^2.17", // 2.21.3
"phpdocumentor/reflection-docblock": "^3.0 || ^4.0", // 4.3.1
"symfony/asset": "4.3.*", // v4.3.2
"symfony/console": "4.3.*", // v4.3.2
"symfony/dotenv": "4.3.*", // v4.3.2
"symfony/expression-language": "4.3.*", // v4.3.2
"symfony/flex": "^1.1", // v1.21.6
"symfony/framework-bundle": "4.3.*", // v4.3.2
"symfony/http-client": "4.3.*", // v4.3.3
"symfony/monolog-bundle": "^3.4", // v3.4.0
"symfony/security-bundle": "4.3.*", // v4.3.2
"symfony/twig-bundle": "4.3.*", // v4.3.2
"symfony/validator": "4.3.*", // v4.3.2
"symfony/webpack-encore-bundle": "^1.6", // v1.6.2
"symfony/yaml": "4.3.*" // v4.3.2
},
"require-dev": {
"hautelook/alice-bundle": "^2.5", // 2.7.3
"symfony/browser-kit": "4.3.*", // v4.3.3
"symfony/css-selector": "4.3.*", // v4.3.3
"symfony/maker-bundle": "^1.11", // v1.12.0
"symfony/phpunit-bridge": "^4.3", // v4.3.3
"symfony/stopwatch": "4.3.*", // v4.3.2
"symfony/web-profiler-bundle": "4.3.*" // v4.3.2
}
}
64 Comments
In my case v2.5.3 all I had to do was:
`
public function testCreatePost()
{
}
`
Seems it was updated by api platform, authentication should be the first check before anything.
Yep, ApiPlatform has changed a some things in its latest version. Thanks for sharing it!
Hello,
FYI, to be able to run the test properly I had to modify your Client::request method like this:
In my case, I had to tweak your code even further.
Hey Julien,
Thank you for sharing your solution with others!
Cheers!
Hey Rakodev
Sorry but I don't fully get the reason of that change. Could you tell me what error are you getting when running the test just as shown in the video?
Cheers!
Hi MolloKhan,
I gave the right headers but when I run the test it didn't get it, so I got this error:
<blockquote>
2019-08-27T14:05:44+00:00 [error] Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException: "The content-type "application/x-www-form-urlencoded" is not supported. Supported MIME types are "application/ld+json", "application/json", "text/csv", "application/hal+json"." at /application/vendor/api-platform/core/src/EventListener/DeserializeListener.php line 128
</blockquote>
The $options['headers'] became like this:
So the final array looks like this before I did the changes:
FYI I don't use your source code in my project.
Here is my actual symfony.lock file:
<a href="https://gist.github.com/rakodev/2b80a2efbdddea8895e1bcb1a7f524e1">https://gist.github.com/rakodev/2b80a2efbdddea8895e1bcb1a7f524e1</a>
Hey Rakodev
I found the reason of this problem. In the latest version of
symfony/http-client(4.3.4) it's a change in the way that headers are parsed, you can see it here (https://github.com/symfony/http-client/commit/92d8add2747e1f1c988550b19ebedf4a9b759450#diff-c31da22ee309f1a4c12290b3965480d2 ). So, the code that Ryan copied from ApiPlatform future version needs to change as well.We have 2 options:
A) Use
symfony/http-client4.3.3 version orB) Adjust the code as you mentioned above
Cheers!
Hey MolloKhan ,
Thank you for your deep dive into the problem.
Interesting that http-client had made a so big change between 4.3.3 and 4.3.4, I thought that the 3rd one was mainly for bug/security fixes.
NP man!
Yeah, probably they didn't realize the impact of the change or they didn't have any other alternative. Who knows...
For anyone getting Error in Evaluate() method of arraysubset inside src/ApiPlatform/Test/
Check your api version if it is greater than 2.4 using
composer show api-platform/core
instead of pasting ApiPlatform inside App just
Use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
paste the above use statement above cheeselistingresource.php inside tests
if you get an error in self::container inside cheeselistingresource.php
use
$container= static::getContainer();
Thanks for another tip Sakshi G. :).
Hey!
I did everything like in this video, even re-did whole project because of some unkown error while trying to test testCreateCheeseListing() function, and I am still getting some error that I can't figure out why it is happening.. I can't progress in this tutorial without proper working phpunit
This is what I get when I try to run php bin/phpunit : https://pastebin.com/4qZ2G7gd
Hey Gediminas N.
I see you have phpunit7.5 however in course code we use phpunit8.2 probably that was a reason, you can safely change signature of method
App\ApiPlatform\Test\Constraint\ArraySubset::evaluate()to match parent method if you want to keep phpunit 7.5 or upgrade it to 8.2 as Ryan did in chapter 10 =)Cheers
I know this will shock you, but I have another error. NOTE: Using docker and followed your instructions in part 3 to setup the test environment which everything seems to be working as expected there.
1) App\Tests\Functional\CheeseListingResourceTest::testCreateCheeseListing<br />Twig\Error\RuntimeError: An exception has been thrown during the rendering of a template ("Environment variable not found: "DATABASE_TEST_URL" in . (which is being imported from "C:\Users\ack\PhpstormProjects\API-Platform-Training2\config/routes/api_platform.yaml"). Make sure there is a loader supporting the "api_platform" type.").So I decided to check:
`C:\Users\ack\PhpstormProjects\API-Platform-Training2>symfony console debug:container --env-vars --env=test
Symfony Container Environment Variables
=======================================
Name Default value Real value
APP_SECRET n/a "$ecretf0rt3st"
CORS_ALLOW_ORIGIN n/a "^https?://localhost(:[0-9]+)?$"
DATABASE_TEST_URL n/a "mysql://root:password@127.0.0.1:32769/main?sslmode=disable&charset=utf8mb4"
// Note real values might be different between web and CLI.`
And in phpunit.xml.dist:
<server name="APP_ENV" value="test" force="true" />So where are common places to check to see what I did wrong?
Hey @Aaron Kincer!
Hmm. If you download the code for this tutorial, there is no DATABASE_TEST_URL that's being used. However, if you downloaded the course code from the next tutorial - https://symfonycasts.com/screencast/api-platform-extending - then we DO use a DATABASE_TEST_URL env var.
That variable can be set in 2 different ways:
A) If you use the same Docker setup as the api-platform-extending tutorial, then you will have a mysql container called
database_test. If you're using the Symfony binary's web server, then this will expose aDATABASE_TEST_URLenv var (assuming docker-compose is running).B) Alternatively, you can manually set
DATABASE_TEST_URLin your .env.test file. If you downloaded the api-platform-extending code, then the .env.test already defaults this variable to equal DATABASE_URL (so that, by default, if you're not using the Docker setup, we just re-use your one database connection for both environments).Let me know if this helps! You're still, kind of, "mixing" different projects together if I understand correctly. Is that correct?
Cheers!
Oh wait. I get it now. I added this to .env.test and it fixed it:
DATABASE_TEST_URL=$DATABASE_URLHey @ Aaron Kincer!
Nice work! But, this might just mean that you're using your normal database also for your tests (which is fine, but not idea).
The reason that DATABASE_TEST_URL is not being exposed when you run your tests is that you need to execute php through the Symfony binary so it can inject the env vars. Try this (which we do in the extending tutorial):
Cheers!
I sort of figured that was what was happening. Makes sense. Took that back out and used the binary to execute php and of course it works. Great way to tie in where you mentioned in a training course the difference between using the symfony binary to do something vs just doing it. Thanks!
The only things I grabbed from the other tutorial was the docker-compose.yaml setup as seen here:
`version: '3.7'
services:
`
and doctrine.yaml under the test config folder:
`# config/packages/test/doctrine.yaml
doctrine:
dbal:
And as I showed above the env for the test environment is indeed exposed. Maybe there's somewhere else I need to define something? Because it looks to me like I have option A going on but something somewhere is missing it.
Is it possible to tie into the router service to generate routes for the test cases?
$client->request('GET', ROUTE_SERVICE);
Hey David B.
What you mean by "tie into the router service"? If you want to add some test routes, I think you can create a
routing.yamlfile insideconfig/routes/testso those routes only exist for the test environmentCheers!
Rather than having to type in '/api/section_items' every time
$client->request('POST', '/api/section_items')Is it possible to use the router service to generate the route ie:
$client->request('POST', $router->getRoute(SectionItem::class))Ah, I understand now. You can use the routing service but you'd still type the *name* of the route, for example "api_users".
Hi,
after the suggestion of ryan to switch ahead to chapter 19&20, I realized that I need to start from chapter 10 because I have to install some libraries (test-pack, symfony/phpunit-bridge, symfony/broser-kit & css-selector, http-client). Actually I have this problem:
Testing Project Test Suite
E 1 / 1 (100%)
Time: 221 ms, Memory: 20.00 MB
There was 1 error:
1) App\Tests\Functional\CheeseListingResourceTest::testCreateCheeseListing
LogicException: You cannot create the client used in functional tests if the "framework.test" config is not set to true.
/var/www/html/vendor/api-platform/core/src/Bridge/Symfony/Bundle/Test/ApiTestCase.php:62
/var/www/html/tests/Functional/CheeseListingResourceTest.php:16
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
I checked the framework.yaml and the test variable is true
Could you help me to resolve it?
Thanks a lot
I tried to remove symfony/test-pack, symfony/phpunit-bridge, symfony/broser-kit & css-selector, then reinstalling only test-pack after removing the vendor folder and a composer cache-clear. Same problem :(
Hey Gaetano S.
Can you double check that you're indeed hitting the test environment on your tests? Check your
phpunit.xml.distfileAnother thing to check is the
framework.yamlfile but the one insideconfig/parameters/test. Or, you can executebin/console debug:config framework --env=test -vvvand look for the "test" parameterLet me know if you still have problems. Cheers!
Hi,
first check:
second check (do you mean config/packages/test?):
Thanks for your help
Hmm, this is interesting because everything looks correct.
I think I need to see your test case to see if I can spot something odd. Another thing to try out is dump the environment inside a test case, just to double check that you're indeed hitting the test environment (by looking at your config I'm positive it's hitting the test environment but just in case)
Another thing you can try is to remove the cache manually and try again
rm var/cache/*Hi,
I tried to remove the cache manually but nothing happened.
This is my test case
I hope it's useful to understand. thanks again
Hey Gaetano,
It looks like you're extending the wrong class, the class name is correct, but the namespace is not. You need
use App\ApiPlatform\Test\ApiTestCase;instead ofuse ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;that you have. In the video, I see we're extending exactlyApp\ApiPlatform\Test\ApiTestCase, I suppose PhpStorm autocompleted the wrong namespace for you :)I hope this helps!
Cheers!
Hi,
After fixing the error about the wrong class, I have still the error. I fall always inside the try-catch of ApiTestCase -> throw new \LogicException('You cannot create the client used in functional tests if the "framework.test" config is not set to true.');
I don't understand why.
Hey Gaetano S.!
Hmm. So this happens because your container is missing a
test.api_platform.clientservice. If you're using API Platform 2.5 (and so, are not using our manually copied test classes that we use in this app, since we are trying to use this API Platform 2.5 feature in a 2.4 app), then this service should be registered automatically for you. Well, it's registered for you automatically, as long as you have this config: https://github.com/symfony/recipes/blob/ec008e83cf1afbbf4a6cd93109fbd83088906d93/symfony/framework-bundle/4.2/config/packages/test/framework.yaml#L2If you're using our copied classes, then you need to add this service manually. We do that right here -https://symfonycasts.com/screencast/api-platform-security/backport-api-tests#registering-the-new-test-client-service - notice the public: true is important.
Let me know if this helps!
Cheers!
Hi,
I'm trying to do this. I have the version 2.5, so I don't need to do anything. Just creating CheeseListingResourceTest and using ApiTestCase of Apiplatform\Core\Bridge\Symfony\Test, is this?. And I have test:true inside the test/framework.yaml. But I have always the same LogicException error. It's incredibly strange. I don't understand where I missed something :(.
Hi again Gaetano S.!
Hmmm. Let's try a few commands to see what the status of your services is:
Also check your
config/bundles.phpfile: which appears first? FrameworkBundle or ApiPlatformBundle? Normally, the order here does not matter. But I noticed that ApiPlatform takes a little shortcut that requires FrameworkBundle to be first. It ALWAYS is, unless someone manually changed it, which is why that's fine. But it's possible that this is your problem.Let me know what you find out!
Cheers!
Hi,
Did you have the possibility to check my answer about the checks to do? Thanks for your help
Hi,
some pictures to show you infos you need -> https://drive.google.com/dr...
Thanks
Hi Gaetano S. !
Sorry for my VERY slow reply - it's been a crazy week :). And excellent screenshots - that's super helpful.
The thing that is very clear now (and wasn't before) is that the
test.api_platform.clientIS present. And... that's interesting - because that's exactly the service that ApiTestCase looks for (and fails if it's not there): https://github.com/api-platform/core/blob/master/src/Bridge/Symfony/Bundle/Test/ApiTestCase.php#L56So... let's do some debugging! First, I'd like you to actually open the core ApiTestCase file - so literally, this file - https://github.com/api-platform/core/blob/master/src/Bridge/Symfony/Bundle/Test/ApiTestCase.php - it will live at
vendor/api-platform/core/src/Bridge/Symfony/Bundle/Test/ApiTestCase.php.Right after this line - https://github.com/api-platform/core/blob/2c87089c4330cd2f571f023fbcc36b5edd2b4dbb/src/Bridge/Symfony/Bundle/Test/ApiTestCase.php#L50 - I'd like you to add:
What does that print? All of your other screenshots indicate that the
test.api_platform.clientIS available. So then... why is it suddenly not available in your test? The only thing I can think of (at the moment) is that (for some reason) the kernel in the test is being booted in some other environment than "test". But... I kind of doubt that's the cause... just because it's a bit hard to misconfigure the tests in this way.Basically... something is going very wrong - it might be some tiny misconfiguration that's giving really bad behavior. And actually, if you're able to (it might be quite big), get a screenshot of the entire kernel object:
Cheers!
I know, that comment is two years old, but I am loosing my mind, because I am getting the same error
This is my framework.yaml
this is my composer.json
and this is my phpunit.xml.dist:
My Unit-tests work just fine, but as soon I want to use the ApiTestCase withe the client I get the error from above, here is the TestCase which is enough to get the error:
I also tried that commands you reccomended for debugging:
Finally I also tried the dumps directy from the ApiTestCase.php
So that seems to be like intended, But the following check in the ApiTestCase.php throws an error:
And that is because 'test.api_platform.client' ist not in the kernel contriner. If I make the following dump from within the ApitestCase.php:
I will get (outsourced that dump from the comment, because it is 1500 lines) :
https://transfer.acted.org/download/77d3156546b2f151/#hjAAKsnSaQ0kBd_xImPKrg
Hey @TristanoMilano!
Oh man, this sounds rough! Immediately, one thing stuck out to me:
That actually does NOT look correct to me. We need the environment to be
test, else we are booting adevcontainer. The 1500 line container dump seems to confirm my suspicion: there is notest.clientservice and it shows that the environment isdev. So, for some reason, your kernel is getting booted in the wrong environment!Unless there are some additional layers in your situation, the kernel is created here - https://github.com/symfony/symfony/blob/584c21016582108e993857cfc0919adc61b468b8/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php#L111-L136 - so you should be able to add some debug statements to figure out why it thinks the environment should be
dev. I've seen people have, without realizing it, some oldAPP_ENV=devreal environment variable set on their system, for example.I hope this helps!
Thanks for the reply. I noticed something interesting, when I do the following dump:
from inside the createKernel fcuntion of the KernelTestCase class, I get the following result:
I do not know why it is set like that, I can not find anything in my code or configs that sets it like that. Every similar Symfony project does not have that behavior. It's a big mistery to me. My hacky/dirty workaround for now is to add this to my TestClass:
But that really gives me headaches :)
Hey @TristanoMilano
That's a bit odd indeed, your workaround may work but that's not the way to change env vars in Symfony. To change an env var for the
testenvironment, you can create a.env.test.localfile and override theAPP_ENVvariableIn theory, you should not need to do this because when you boot the kernel in a test case, Symfony uses the
testenvironment by defaultI hope it helps. Cheers!
Thank you for your reply. Using .env.test.local and setting
in there was what I tried before. But that still lead to that error.
Because in that case the following dump from inside KernelTestCase
still returns:
That is all very, very strange.
What do you get if you dump the environment from the $kernel object (after instantiating it)
I'm assuming you're inside a PHPUnit WebTestCase
When I do this:
from inside a TestCase that extends ApiTestCase I get:
So for now I have to go with my dirty workaround. I do not get why. Have a dozen of similar apps running that do not behave like that.
I can't get that one debugged :(
Hey TristanoMilano,
Check your .env files, probably you override Symfony environment there somehow? Also, check for phpunit.xml files you have in the project - probably there might be also overwritten Symfony env?
Also, during running those tests could to turn off Symfony web server? i.e. to make it does NOT server your 127.0.0.1 host. I wonder if tests will still work and show dev env - probably in your tests you send a really API request to the 127.0.0.1 ? And if that address serves your website in dev env - that makes sense you see "dev" env in your tests :)
I hope this helps!
Cheers!
Hi Ryan,
don't worry about your reply. You have a lot of things to do, other users needs your helps. If I have to wait, I do. I updated the folder of screenshots. I understand a little bit more the problem. I mean, I know how to change the env. Basically, when I run the docker-compose, the service read the env.local with APP_ENV=..... If I put there 'test', I can running phpunit test with the env->test. Or better, I put 'dev' and I run unit tests in this way -> APP_ENV=test php bin/phpunit. And now test passed. Ok, I have an error:
-> [error] Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\HttpException: "Full authentication is required to access this resource." at /var/www/html/vendor/symfony/security-http/Firewall/ExceptionListener.php line 198
but I think it is normal because I need to create a user, auth and so on. I have to continue with the tutorial. I don't know how to thank you. I owe you a dinner. If you pass in the south-est of France (Cote d'Azur), you are welcome :). See you at my next error and thanks again.
Hey Gaetano S.!
> don't worry about your reply. You have a lot of things to do, other users needs your helps
I *do* really appreciate this :). We try to help in the comments because we like helping... but if we're going to do it, we also like to be timely ;).
> Or better, I put 'dev' and I run unit tests in this way -> APP_ENV=test php bin/phpunit. And now test passed
Yep, this makes (mostly) a lot of sense: your app will run in "dev" mode normally, but you are overriding it when you run the tests. The Docker setup was actually the missing piece for me to understand this thing fully! So normally, if you do nothing, your tests will automatically execute in the "test" environment - you can see that here - https://github.com/symfony/...
But, if you set a real APP_ENV environment variable (which Docker will do if you point it at the .env.local file), then the test will use THAT instead. THAT is why you had the problem: your app was using the env var set by Docker instead of defaulting to test. Oh, the complexities of modern setup and env vars :).
> -> [error] Uncaught PHP Exception Symfony\Component\HttpKernel\Exception\HttpException: "Full authentication is required to access this resource." at /var/www/html/vendor/symfony/security-http/Firewall/ExceptionListener.php line 198
So this means basically what it says: you're trying to access an endpoint that requires authentication, but you are not logged in. Do you get this when you run the tests? Or when you use the API in a browser? If in the browser, you can go to the homepage and log in there.
> I owe you a dinner. If you pass in the south-est of France (Cote d'Azur)
Well that sounds lovely! I can't wait until the world has the normalcy to visit France again (have never been to the South of France!).
Cheers!
Hi,
I did get the error on running tests. When I have time, I will go on. You know..my job, my children :).
Cheers!
Ah! You are right....I'm sorry, my fault...and I'm sorry, Diego. I noticed that I mess up a little bit all folders about tests. I need to restart and try to fix everything. Thanks again. I let you know if I will do dumb stuff :).
"Houston: no signs of life"
Start the conversation!