If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeOur test is already pretty cool. This is called a smoke test: with just a tiny bit of code, we're at least making sure the homepage doesn't have a huge error!
And now... stop! Before we write any more tests, we need to ask ourselves a question: does the feature we're building need a test? We're going to add a list of all of the enclosures on the homepage. That doesn't sound too scary, so I might not test this in the real world. We will test it... yea know... because this is a tutorial on testing. But my point is: think before you test!
Ok, back to TDD! Our homepage is blank... but soon it will have a list of all of the enclosures in the database!
In the test, we need to think about how this might look. Let's add $table = $crawler->filter()
and then a CSS selector: .table-enclosures
. I'm saying that, when we build this page, we should create an element with this class. The $crawler
object is a bit similar to the jQuery
function in JavaScript: by using its filter()
method, it's really good at finding elements via CSS. The $table
variable is itself another Crawler
object, which represents the table element.
... lines 1 - 6 | |
class DefaultControllerTest extends WebTestCase | |
{ | |
public function testEnclosuresAreShownOnHomepage() | |
{ | |
... lines 11 - 16 | |
$table = $crawler->filter('.table-enclosures'); | |
... line 18 | |
} | |
} |
Now, we can assertCount()
that 3 is equal to $table->filter('tbody tr')
. In other words, inside the table, we expect there to be 3 rows. Why 3? Well... I just made that up! Just like with integration tests, we're going to need to take control of the database so that we know exactly what's inside. More on that soon!
... lines 1 - 8 | |
public function testEnclosuresAreShownOnHomepage() | |
{ | |
... lines 11 - 17 | |
$this->assertCount(3, $table->filter('tbody tr')); | |
} | |
... lines 20 - 21 |
Try the test now:
./vendor/bin/phpunit tests/AppBundle/Controller/DefaultControllerTest.php
Yay! It fails! That means we are ready to code!
Open DefaultController
and query the database for all the enclosures: $this->getDoctrine()->getRepository(Enclosure::class)->findAll()
. Use this to pass a new enclosures
variable into Twig.
... lines 1 - 2 | |
{% block body %} | |
<h3>Enclosures</h3> | |
<table class="table-enclosures"> | |
<tbody> | |
... lines 8 - 15 | |
</tbody> | |
</table> | |
{% endblock %} |
Now open that template! It's in app/Resources/views/default/index.html.twig
. I'll add an h3, the table with class="table-enclosures"
and a tbody
.
... lines 1 - 2 | |
{% block body %} | |
<h3>Enclosures</h3> | |
<table class="table-enclosures"> | |
<tbody> | |
... lines 8 - 15 | |
</tbody> | |
</table> | |
{% endblock %} |
Inside, start looping! for enclosure in enclosures
. For the <tr>
, I'm going to give each a unique id. This will help us write a different test in a few minutes.
... lines 1 - 5 | |
<table class="table-enclosures"> | |
<tbody> | |
{% for enclosure in enclosures %} | |
<tr id="enclosure-{{ enclosure.id }}"> | |
... lines 10 - 13 | |
</tr> | |
{% endfor %} | |
</tbody> | |
</table> | |
... lines 18 - 19 |
And now... let's print some stuff! Like the Enclosure #
, and on the next column, "Contains" then enclosure.dinosaurCount
dinosaurs. Rawr!
... lines 1 - 7 | |
{% for enclosure in enclosures %} | |
<tr id="enclosure-{{ enclosure.id }}"> | |
<td>Enclosure #{{ enclosure.id }}</td> | |
<td> | |
Contains <strong>{{ enclosure.dinosaurCount }}</strong> dinosaur(s) | |
</td> | |
</tr> | |
{% endfor %} | |
... lines 16 - 19 |
PhpStorm is angry... and it's right! We don't have getId()
or getDinosaurCount()
methods yet.
Open up Enclosure
. Near the top, at getId()
: it should return a nullable int. And at the bottom, create a public function getDinosaurCount()
that will return an int
. Return $this->dinosaurs->count()
.
... lines 1 - 14 | |
class Enclosure | |
{ | |
... lines 17 - 44 | |
public function getId(): ?int | |
{ | |
return $this->id; | |
} | |
... lines 49 - 94 | |
public function getDinosaurCount(): int | |
{ | |
return $this->dinosaurs->count(); | |
} | |
} |
So... does the page work? It should! Try the tests!
./vendor/bin/phpunit tests/AppBundle/Controller/DefaultControllerTest.php
Ah! Failure because the actual size one does not match expected size 3. Check out the homepage in the browser: we have 7 enclosures! This is the same problem we had with integration test: we're not taking control of the data in the database. So... we really have no idea how many enclosures will be in the list! Our main database has 7... and apparently our test database has only one.
Let's fix this!
Hey Angelika,
Difficult to say, I haven't seen a similar error before. It sounds like some possible incompatibility in newest versions you upgraded. Did you download the course code and started from the start/ directory? Or do you follow this course on your personal project or from scratch?
How exactly did you upgrade your dependencies? Did you change anything in composer.json or just ran "composer update" command? If you changed "composer.json", what exactly did you change? Could you try to upgrade the dependencies one more time? Probably it's a known bug that was already fixed.
Also, looks closer to the error stack, it can give you some hints about the error. If you still have this error - please, share the full error stack so we have more information about this error.
I hope this helps!
Cheers!
I don't know how to debug this command (to get the full stack of the error), I copied all I got. I get this error when running php bin/console server:run or any command with bin/console in my console. I started with the start directory and edited it according to the course, it used to work for some time, I had the invitation page, then I had some conflicts between dependencies, so I copied dependencies from the "versions" tab and run composer update. I am not sure what changed in the file, I guess many things (versions). I tried rerunning composer.json, it doesn't help. I get the same error on ScriptHandler::clearCache (this time two times). I will try with the start composer.json and all the installation commands.
Hey Angelika,
This sounds like you have some version conflicts in your project, probably you solved the conflicts between dependencies not perfectly. I'd recommend you to replace your composer.json and composer.lock files with the ones from the start/ directory of the course downloads. Then, run "composer install" to install all the dependencies, and then run "composer require" to install any dependencies you're missing on the current step. This should help
Cheers!
it is interesting that you are repeating this "think before you test if you actually need it". I have never seen such testing tutorials which would tell this :) but that is good probably that you do it, because those other tutorials which do not say this, made us less productuve programmers :( and productivity is super good skill and often valued more than quality by those who pay money. And without this it feels like the more you learn, the less valued you get which is annoying really.
Hey Lijana Z.!
I'm really glad you have this perspective! Testing is just a tool - it's a *cool* tool, but it's not everything, and (like anything) can be used too much! Everyone will find their own balance and I want people to realize this - to realize that there *is* a way to do "too much testing" and to, hopefully, think critically like obviously have done :).
Cheers!
Hey Coder,
Hm, try to open this page again: https://knpuniversity.com/s... and click on "Conversation" tab - it should be there :)
Cheers!
// 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
}
}
I have problem with running server after updating composer.json according to "Versions" tab and running "composer update". I get: [Symfony\Component\Console\Exception\LogicException]
An option named "connection" already exists.
What can I do? I didn't find much in Google.