Chapters
29 Chapters
|
2:54:09
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!Compatible PHP versions: ^7.0, <7.4
Subscribe to download the code!Compatible PHP versions: ^7.0, <7.4
-
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!
20.
Integration Tests
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.
While the fundamentals of PHPUnit haven't changed, this tutorial *is* built on an older version of Symfony and PHPUnit.
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": "^7.0, <7.4",
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/doctrine-bundle": "^1.6", // 1.10.3
"doctrine/orm": "^2.5", // v2.7.2
"incenteev/composer-parameter-handler": "^2.0", // v2.1.2
"sensio/distribution-bundle": "^5.0.19", // v5.0.21
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.28
"symfony/monolog-bundle": "^3.1.0", // v3.1.2
"symfony/polyfill-apcu": "^1.0", // v1.6.0
"symfony/swiftmailer-bundle": "^2.3.10", // v2.6.7
"symfony/symfony": "3.3.*", // v3.3.13
"twig/twig": "^1.0||^2.0" // v2.4.4
},
"require-dev": {
"doctrine/data-fixtures": "^1.3", // 1.3.3
"doctrine/doctrine-fixtures-bundle": "^2.3", // v2.4.1
"liip/functional-test-bundle": "^1.8", // 1.8.0
"phpunit/phpunit": "^6.3", // 6.5.2
"sensio/generator-bundle": "^3.0", // v3.1.6
"symfony/phpunit-bridge": "^3.0" // v3.4.30
}
}
31 Comments
I get this error when I am running this test. Can you suggest what is wrong?
Fatal error: Declaration of Symfony\Bundle\FrameworkBundle\Test\KernelTestCase::tearDown() must be compatible with PHPUnit\Framework\TestCase::tearDown(): void in /var/shared/app/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php on line 221
I updated symfony to 3.4 and phpunit-bridge to ^3.3@dev, with php on 7.1 and phpunit to 8.1, and now it works for me correctly.
Hey Dennis,
It looks like an easy fix, you just need to match the signature of parent TestCase::tearDown() method in our KernelTestCase::tearDown(). You need to tweak the method signature to:
as you can see here: https://github.com/sebastianbergmann/phpunit/blob/f462942d1cc58cc02e2c1a247d648c215c208354/src/Framework/TestCase.php#L417-L422
Cheers!
Another option, perhaps the most sensible, is to use the same version of phpunit as the tutorial, the 6.3
A dumb, basic question: how do I configure my test environment to use a mysql database that is running inside a docker container? I created a second database for testing inside the same container as my dev db, but I'm baffled as to how to get my tests to communicate with it.
That is, I have a <i>dev</i> database service called ´database' set up in docker-compose.yaml, and when I need CLI access to it, I just say
docker-compose exec database mysql -umy_username --password=my_password my_dev_db_nameand don´t need to worry about the port number. So I don't know how to craft a DATABASE_URL to put in my.env.test.local.OK after about 4 hours of hell I think I might have an answer, maybe you can tell me if I am more or less right. You don´t explicitly set DATABASE_URL yourself.
1) inside the docker container, create a database with the same name as your dev database plus the suffix _test (e.g., my_dev_db_test)
2) inside the docker container, give your dev user full privileges on my_dev_db_test
3) run symfony console doctrine:database:create --env=test
4) run symfony console doctrine:fixtures:load --env=test
5) the coup de graçe that gave me the most trouble: run tests with the command symfony php vendor/bin/phpunit
Hey David,
Yes, all your listed sounds correct! Actually, with the full privileges DB user you can create DB with symfony command you mentioned in step 3. So, the 1st step is redundant then. And yes, when we're talking about Docker - try to use symfony CLI everywhere where possible, as it takes care of setting up env vars correctly for you.
Cheers!
Victor! Sorry to go off-topic but it's good to hear from you, and I fervently hope you and all your people (loved ones, and all the rest) are doing OK under the circumstances, which by all reports are horrendous.
Hey David,
Yes, this is a really hard and horrendous time, probably not only to us but also and to the whole world because the conflict might expand quickly. I'm OK, people are heroically standing, government still does its best I think. Thank you for mentioning this!
Cheers!
How to separate integration tests from unit-tests?
You located your integration test in the folder '/tests/' which is standard for unit-test.
So every run of PHPUnit will run all of them.
Usually integration test are located in different folder or somehow marked so fast unit-tests can be executed separately from time-consuming integration tests.
What is a best practice in Symfony?
Hey Eugene V. Kaurov!
I don't think there is one best practice for how to organize these test directory. Personally I organize integration and unit tests in the same way without any specific separation. If you want to be able to execute the unit tests independently from the integration tests, you could use PHPUnit groups above the classes or methods - e.g.
@group integration. Of course, it would also be totally fine to create a structure liketests/integration/if you like that better :).Cheers!
The service's public alias is such a good and ingenious idea!
Thank you, I was trying to mock the IO during an integration testing, your solution made my day!
Hey, Bruno! I'm glad you liked the idea! :)
How would you test form submission? I mean only test the entity is created correctly, or waiting entity insertion into DB then fetch it back and compare, thanks.
Hey Yvon,
It depends, usually devs do not test setters, but if we're talking about form validation - it makes sense. But usually testing that form is valid and entity is actually created in the DB is a better choice, because you may forget to add some validation constraints and form will pass validation but the DB query is failed because of SQL validation constraint.
Cheers!
nice to hear that solution, thanks !
Hey Yvon,
You're welcome! But keep in mind that it may be more resource consuming, as you would need to send queries to the DB, and it takes some time, so your tests may become slower. But as always, look for a good balance. Just don't blindly test everything :) Though, if your project is small, or you just want to practice testing, or this feature is really important in your application - why not to test it ;)
Cheers!
well if it can save me some big stress, I would not hesitate, I don't have much time so I will focus on the most important tests
Hey Yvon,
That's a good strategy to focus on important features first 👍
Cheers!
Hello,
I think a single quote "`" is missing in the script after the word "Security" in:
Find `Security and copy the id field. Open Dinosaur and paste this in. Do the same for Enclosure`.
Hey AmalricBzh
You're 100% correct. I'll fix that ASAP
Thanks for reporting it. Thanks!
Hi!
When I run last test, I get this result
1) Tests\AppBundle\Service\EnclosureBuilderServiceIntegrationTest::testItBuildsEnclosureWithDefaultSpecifications
AppBundle\Exception\NotABuffetException: Please do not mix the carnivorous and non-carnivorous dinosaurs. It will be a massacre!
When I repeat this test several times, it sometimes passes.
This is because we generate random dinosaurs at EnclosuBuilderService->addDinosaurs().
Bug?
Hey avknor
Oh, yes, you are right, this line is causing the troubles
we are going to add a note about it. Thanks for informing us about that pesky bug :)
Cheers!
What is the correct way to avoid this error, without creating a new one?
Hey Arne K. !
To fix the problem of EnclosureBuilderServer "mixing" carnivorous and non-carnivorous dinosaurs, we made a small tweak to the
EnclosureBuilderService::addDinosaur()method. Basically, we just moved the$diet =line up a few lines so that when we add theforloop later, this part is not in the loop. In the tutorial, we copy the originalEnclosureBuilderServicefrom atutorial/directory, and if you download the course code, you'll get the updated version. You can also see the updated version here - https://symfonycasts.com/screencast/phpunit/full-mock-example#codeblock-2505d8fa36 (and if it's helpful, you can see the diff here: https://github.com/knpuniversity/phpunit/commit/ceca8a69b81cfa240cf0b6cd9d3ea92dc2b2fd65).After we add the for loop, the final product looks like this: https://symfonycasts.com/screencast/phpunit/full-mock-example#codeblock-aabfeeaf56
Let me know if that helps! It was a silly detail we missed, and we don't want it to cause any real issues!
Cheers!
I've got a question but not sure if this is the correct lesson to do it. Here it goes.
Integration tests you test the relation between the DB and you code. So, you kind of picture the database for each specific test, it does make sense and it's all right.
What about API? what should I test when I'm using an API on my code?
My current approach is call the API properly, parse and test the content.
Does it sound it right?
thanks
Hey Felipe L.
When you are testing an API integration there are a couple of ways you can do it and it depends on your needs
- Mock the API response. In this case you don't hit the API but you test all the scenarios, when the response was successful, when there was an error, etc.
- Some API's comes with a sandbox, in that case it's totally fine to hit the sandbox and your test will behave almost as in production (I say almost because I've seen some sandboxes that doesn't behave exactly the same as production)
- Hit production API endpoints but using a different account. This some times is useful when the integration to the API is super critical for your application.
Cheers!
Hi MolloKhan , thanks for your reply.
If I'm not mistaken, I've tested mocking API response and definitely tested hitting the production API.
But never tested using a sandbox, I'll have a look at it anyway.
cheers
Cool! So you already know how to test an API integration :)
BTW, not all API's comes with a sandbox, it depends on the third party platform
Cheers!
Hi,
I get the following error when I am running this test, and I can't figure it out!
vagrant@phpunit:~/code/phpunit$ ./vendor/bin/phpunit --filter testItBuildsEnclosureWithDefaultSpecification
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.
E 1 / 1 (100%)
Time: 3.66 seconds, Memory: 26.00MB
There was 1 error:
1) Tests\AppBundle\Service\EnclosureBuilderServiceIntegrationTest::testItBuildsEnclosureWithDefaultSpecification
Doctrine\ORM\ORMInvalidArgumentException: Expected value of type "Doctrine\Common\Collections\Collection|array" for association field "AppBundle\Entity\Enclosure#$securities", got "AppBundle\Entity\Security" instead.
/home/vagrant/code/phpunit/vendor/doctrine/orm/lib/Doctrine/ORM/ORMInvalidArgumentException.php:206
/home/vagrant/code/phpunit/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:840
/home/vagrant/code/phpunit/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:740
/home/vagrant/code/phpunit/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:452
/home/vagrant/code/phpunit/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:765
/home/vagrant/code/phpunit/vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:340
/home/vagrant/code/phpunit/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:356
/home/vagrant/code/phpunit/src/AppBundle/Service/EnclosureBuilderService.php:43
/home/vagrant/code/phpunit/tests/AppBundle/Service/EnclosureBuilderServiceIntegrationTest.php:23
ERRORS!
Tests: 1, Assertions: 0, Errors: 1.
vagrant@phpunit:~/code/phpunit$
I have pushed my code here in case you need to see it... https://github.com/shauntho...
Yo Shaun T.!
Ah, this was TRICKY! You're not going to like the answer.... :D. Because the tiniest bugs are the hardest to find. Btw, thanks for posting your code - it was the only way I could find the small typo! Here it is - in
Enclosure.php:Yep... it was simply that the relationship was mapped to expect a collection of Enclosure, not a collection of Security objects. Doctrine checks exactly for this, but the exception it throws is honestly not quite as clear as it could be. Hopefully this unblocks you :D.
Cheers!
"Houston: no signs of life"
Start the conversation!