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!
09.
Handling Object Dependencies
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
}
}
21 Comments
Btw so far TDD looks easy with those simple code examlples. But to get a good tutorial, I think you should to take some class from real complex business project and add or modify some feature. I would like to see how its done there. And take some bit more legacy code which needs a bit of refactoring. Thats where I struggle with TDD.
Yes, you are right!
Hey Lijana Z.!
Yea, we try to make things as realistic as possible, but there are always "uglier" situations out in the "wild". In your situation, if you have legacy code that needs refactoring, then this likely means that it does not have any tests yet. So, TDD is a bit different in this case. Really, you have a few options: (1) trying to add some tests to the existing code to make sure you don't break anything and then doing TDD with the new feature change or (2) trying to extract the complex part into a new class and do TDD there, leaving all of the other, old logic in its original location.
It's hard to describe, but *when* I do TDD (which, as you know is far from always), it is in situations that feel very natural. What I mean is, it is in situations where the business logic requires a class/function that has various input and various output. So, I naturally *want* to do TDD in these situations: where I can test all the input / output before writing the code. In other situations, where the class/function I need to write does *not* have a lot of input/output variations (e.g. maybe a function that does 1 thing, saves something to a database, then does 1 other thing), I often won't test it directly. Honestly, a lot of our tests are ultimately functional tests, because the individual units are not that complex, but we want to make sure the feature works. We more often do TDD with functional tests. For legacy code, this would mean first writing a functional test to see that the existing feature works, then write a new functional test for the new feature, then coding that feature. TDD... but on the functional test level.
Cheers!
ok.
Hey Lijana Z.
If you constantly work with wild legacy code, I recommend you this book: https://www.amazon.com/Work...
It's pretty good :)
Cheers!
I don't now, but I believe in future probably everyone need to work with legacy code over their carreers. Unless you are chnaging jobs once you get legacy project :)
haha, yeah, we all will work on a legacy project eventually, but the intention is to be able to start new projects where the base code will not rot, or to improve old projects little by little.
Once again, read that book, you will find a lot of tricks when working with legacy code :)
When we test the functionality to add dinos into our enclosure, no parameters are passed into the Dinosaur's constructor...but it has parameters!
How didn't the tests fail when they were executed?🤔
Hey Abelardo
You're watching closely ;) - That's because both arguments of the Dinosaur's constructor are optional, so if you don't pass any, it will use the default values instead
Cheers!
Yes, I watched the video where both parameters were initialized by default with "Unknown" and false respectively.
Thanks!
Best regards.
I'm going to rewatch the prior videos because I didn't realize when those parameters were set as optionals.
Thanks for your reply.
Cheers!
About mocking model-objects (in my case Doctrine entities): The service which I'm testing makes use of the auto-generated ID of the provided entity. However, the Doctrine entity does not have a setId()-method, so setting an ID just for testing is not possible. That's a problem, because when I feed the entity to my service, the service can't read the entity ID and explodes...
Would you mock the entity, in such a case? Or would you apply some other best practice, here? And if I should create a mock, is it possible to create a mock based on an instance of my entity-class, so I don't have to put a lot of ->willReturn()'s on my mock?
Hey Thijs-jan V.
That's a good question and there some options you can take
1) Just add a
setId()method to the entity but add a PHPDoc @internal flag, so you indicate that such method is only for testing purposes2) Use Reflection to set whatever value you want on the
idproperty3) You can mock an entity class, although it's not recommended, it's still valid when you have a complex situation and using a mock just make life easier
4) Refactor your code so it works with the ID value instead of the entity object
You can pick whichever fits better your needs. Cheers!
it seems like something has changed with a newer library versions, code below (EnclosureTest, line 25) does not pass the test:
<br />$this->assertEquals(2, $enclosure->getDinosaurs());<br />with the following error:
<i>1) Tests\AppBundle\Entity\EnclosureTest::testItAddsDinosaurs Doctrine\Common\Collections\ArrayCollection Object (...) does not match expected type "integer".
</i>
although it works with explicit integer value:
<br />$this->assertEquals(2, $enclosure->getDinosaurs()->count());<br />Hey _zippp
Looks like your line 25 is a little bit different. In course code Line 25 is:
$this->assertCount(2, $enclosure->getDinosaurs());It's
assertCount()notassertEquals(), so probably code you got some outdated code somehow. You can just fix this line, or download course code again to be sure that everything is in sync.Cheers!
There is a mistake in the code of this chapter: when we make annotations for enclosure and dinosaurs in the entities Dinosaur entity is covered two times.
Hey toporovvv
What annotations are you talking about? About the relationship between Dinosaur and Enclosures? If that's the case, we are just declaring the inverse side of the relationship.
Have a nice day.
I'm talking about the code below this text:
"Now, above the $dinosaurs property, use @ORM\OneToMany with targetEntity="Dinosaur", mappedBy="enclosure" - we'll add that property in a moment - and cascade={"persist"}."
There should be Enclosure entity, but there is a Dinosaur.
Then, below this code and after the text block - "In Dinosaur, add the other side: private $enclosure with @ORM\ManyToOne. Point back to the Enclosure class with inversedBy="dinosaurs" - exactly the same code as above.
Ohh I see it!
It's already fixed now, thanks for informing us about that bug.
Cheers!
Interesting about mocking entities. I had heard that we should not mock it, but when entities used to have some function which is not getter or setter, I felt like I need to mock that. So I learned that we can mock them. I used to mock them, but I thought I was doing poor tests and code was poor in entiy because it was having function other than getter and setter. I thought problem is that it is not good for tests if entity has other than getter and setter function.
Hey Coder,
It depends, but I think as far as your functions in entities simple and useful - it's ok to have them there. And yes, you need to think about mocking entities only when you really need it, i.e. when it's much simpler to mock entity instead of setting proper data to it, but in most cases you probably don't need to do that ;)
Cheers!
"Houston: no signs of life"
Start the conversation!