Buy

PHPUnit: Secure the Park

Let me paint you a scary picture:

It's Friday night. It's stormy. The office is empty and you're deploying fresh code straight to production. Suddenly, an alarm! What? The fences are down!? The dinosaurs are escaping!? Somehow, your beautiful code contained a bug. And as the raptors surround you, one thought keeps coming back: if only you had written tests.

I hate bugs, I hate fixing emergencies on production, and I especially hate being eaten by raptors.

It's time to go pro with coding... and that means, learning to test! And not just because we hate running from dinosaurs. We want to write code that is thoughtfully-designed and have the ability to add new features with confidence.

Hello Dinosaur Park

To make this dream come alive, you should totally code along with me. Download the course code from this page. After unzipping the file and turning the fences back on, you should find a start/ directory that has the same code you see here. Open up the README.md file for setup instructions and directions on how to catch the last boat off the island before the storm.

The last step is to find a terminal, move into your project, and run:

./bin/console server:run

to start the built-in PHP web server. In your browser, go to http://localhost:8000 to find... well... nothing! Just, "Welcome to Dinosaur Park". Instead of creating a park full of dinosaurs and then worrying about security... ahem... we don't have any code yet. We're going to build this dino factory and write tests all at the same time.

Installing PHPUnit

The de facto standard tool for testing in PHP is PHPUnit. Open a new terminal tab. Install it with:

composer require --dev phpunit/phpunit

This will obviously download the PHPUnit library into your vendor/ directory. But mostly, you will interact with PHPUnit as an executable. When this finishes, you can now run:

./vendor/bin/phpunit

Hi PHPUnit! And hello Sebastian Bergmann and other contributors! There are no tests yet but I already feel like we're making friends.

Write some Tests

Let's write our first test. But, uh, don't worry about what we're testing yet - let's just experiment a little.

Create a tests/ directory and inside, another AppBundle/Entity directory. We'll talk about this structure soon, but first we have dinosaurs to contain!

Add a new PHP class: DinosaurTest, and give it a namespace: Tests\AppBundle\Entity. Make sure you extend a class: TestCase from PHPUnit.

14 lines tests/AppBundle/Entity/DinosaurTest.php
... lines 1 - 2
namespace Tests\AppBundle\Entity;
... line 4
use PHPUnit\Framework\TestCase;
... line 6
class DinosaurTest extends TestCase
{
... lines 9 - 12
}

To actually make a test, create a public function called testThatYourComputerWorks. We're giving it that name because, inside, we're going to say $this->assertTrue(false).

14 lines tests/AppBundle/Entity/DinosaurTest.php
... lines 1 - 6
class DinosaurTest extends TestCase
{
public function testThatYourComputerWorks()
{
$this->assertTrue(false);
}
}

If this test passes, you'll know to throw your computer out of the window and buy a new one. Let's find out. To run the tests, find your terminal, and re-run PHPUnit:

./vendor/bin/phpunit

Yes! It fails! My computer gets to live! It failed asserting that false is true on DinosaurTest line 11.

Test Rules & Best Practices

Ok, let's talk about the basic rules of writing a PHPUnit test. First, you can technically put your test classes anywhere... but.. you've gotta admit that tests/ is a pretty good place. Actually, in a Symfony project, you automatically start with a phpunit.xml.dist file. Well, in Symfony 4, this is added when you install phpunit. We'll talk more about this file later... but PHPUnit reads this automatically. And... check it out! It says that our tests all live in... tests/. That's how PHPUnit is able to find our DinosaurTest.

Second, our test has a namespace... but that's not really important. In a Symfony project, your composer.json file has an autoload-dev section that basically says that anything in tests/ should start with the namespace Tests. No big deal.

Let's get to the really important stuff, because PHPUnit does have a few crucial rules. First, your test class must extend TestCase and end in the word Test. Second, all of your test methods must be public and start with the word test. When you run PHPUnit, it basically looks for all classes ending in Test and all public functions inside starting with test.

Got it? Good... because the storm is coming, and we've got work to do. Delete the fake test. Let's start coding.

Leave a comment!

  • 2017-11-07 weaverryan

    Hey there!

    Ah, thanks for the feedback! Leanna *is* actually a developer, though you're correct that she isn't the person who originally wrote these tutorials. And the jokes are actually a mixture of jokes she wrote, that I wrote and also some that Andrew wrote (he's awesome at this!). So, I know it's a different voice than on most of the tutorials, but I love having her variety and personality mixed in on some of our courses :). But, we *are* going to look into the "s" sound & microphone placement to see if we can improve on that.

    Cheers!

  • 2017-11-07 ann.

    Sorry guys for these critics :(
    My co-workers and me have the same problem.
    It is big difference between Ryan tutorials( maybe because he is a developer ) and voice of this girl - totally unnatural ( because she is not a developer).
    When she speaks I always hear this "word ssssss, word ssssssss, word sssssss", maybe she is very close to microfone.
    I checked old tutorials and the same issue. The same girl again in action :)
    If you compare one of Ryan tutorial and this one, it is a huge difference.
    Somebody (developer) wrote text and she tries to read, her jokes without emotions are totally unnatural.

  • 2017-11-07 weaverryan

    <3 this so much! What a great example of a way that tests help you that you don't realize until you really dive into them.

  • 2017-11-07 Milan Vlach

    Another good example why creating tests during your development process (quite a different one than getting eaten by a Dino :)) is when you are developing a new technology you are not familiar with, and instead of writing a testing environemt (a class or function that does everything you need), you can write the UnitTests or the FunctionalTests which would test each and every aspect of your new logic.

    What is so good about this approach?
    - Well, it helps you think on the most elementary level - what your logic REALLY needs and not getting tangled inside a labyrinth.

    All of this approach expects that you write tests before you write your logic. Now, I myself consider more comfortable to image and think about every aspect of my application before I start coding it and consider it good practise - It's up to you (YOU THE READER) which approach is more comfortable for you.
    You hold the reins of your universe in your own hands, mate :)

  • 2017-11-07 Jelle Schouwstra

    Oh I am SO looking forward to this!