Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

PHPUnit Install

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Hey everyone! Welcome to PHPUnit: testing with a bite! The tutorial where we discover, to our horror, that yet another Dinosaur theme park has built their systems... without any tests. It won't matter whether or not the raptors can open doors... if the fences never turn on.

Our park is called Dinotopia. And, to help wrangle our prehistoric friends, we've written a simple app that shows us which dinos are where and... how they're feeling. As you'll see, it's great! Except for the complete lack of tests.

App Setup

Anyways, to learn the most about testing and guarantee that nothing deadly will escape from your application, you should code along with me. After clicking "Download" on this page, unzip the file and move into the start/ directory to find the code you see here. Check out the README.md for all the setup details.

The last step will be to open up a terminal and run:

symfony serve -d

to start a local web server on port 8000.

Cool! Move over to your browser, open a tab, go to localhost:8000... and yes! Our Dinotopia Status app!

The App: Dinotopia Status

This simple app has the name of each dino, genus, size, and which enclosure the dino is currently hanging out in. Down here at the bottom, we also have a link to GenLab's super secret dino-park repository on GitHub. OoooO. This is where the engineers regularly post updates to let Bob, our resident park ranger, know which dinos are feeling good, need their medicine, or have escaped. Wait, What?! Hopefully, GitHub doesn't go offline when that happens.

And that's where we come in! We've already built the first version of the Dinotopia Status app. Looking at the code behind this, it's pretty simple: one controller

... lines 1 - 2
namespace App\Controller;
use App\Entity\Dinosaur;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class MainController extends AbstractController
#[Route(path: '/', name: 'main_controller', methods: ['GET'])]
public function index(): Response
$dinos = [
new Dinosaur('Daisy', 'Velociraptor', 2, 'Paddock A'),
new Dinosaur('Maverick','Pterodactyl', 7, 'Aviary 1'),
new Dinosaur('Big Eaty', 'Tyrannosaurus', 15, 'Paddock C'),
new Dinosaur('Dennis', 'Dilophosaurus', 6, 'Paddock B'),
new Dinosaur('Bumpy', 'Triceratops', 10, 'Paddock B'),
return $this->render('main/index.html.twig', [
'dinos' => $dinos,

one Dinosaur class...

... lines 1 - 2
namespace App\Entity;
class Dinosaur
private string $name;
private string $genus;
private int $length;
private string $enclosure;
public function __construct(string $name, string $genus = 'Unknown', int $length = 0, string $enclosure = 'Unknown')
$this->name = $name;
$this->genus = $genus;
$this->length = $length;
$this->enclosure = $enclosure;
public function getName(): string
return $this->name;
public function getGenus(): string
return $this->genus;
public function getLength(): int
return $this->length;
public function getEnclosure(): string
return $this->enclosure;

and exactly zero tests. Our job is to fix that. We're also going to add a feature where we read each dino's status from GitHub and render it. That'll help Bob avoid going into the enclosure of Big Eaty - our resident T-Rex - when his status is "Hungry". Those accidents involve a lot of paperwork. And thanks to our tests, we'll ship that feature bug-free. You're welcome, Bob!

If you're new to testing, it can be intimidating. There are Unit tests, functional tests, integration tests, acceptance tests, math tests! The list is almost endless. We'll talk about all of these - except for math tests - throughout this series. In this tutorial, we're going to zoom in on unit tests: tests that cover one specific piece of code - like a function or method.

Oh, and by the way, tests are also super fun. It's automation! So buckley up.

Installing PHPUnit

What's the first step to writing tests? Installing PHP's defacto standard testing tool: PHPUnit. Move over to your terminal and run:

composer require --dev symfony/test-pack

This test-pack is a Symfony "pack" that will install PHPUnit - which is all we need right now - as well as some other libraries that'll come in handy later.

After it finishes, run:

git status

Cool! In addition to installing the packages, it looks like some Symfony Flex recipes modified and created a few other files. Ignore these for now. We'll talk about each one at some point in this series when they become relevant.

Ok, we're ready to write our first test! Let's do that next.

Leave a comment!

Login or Register to join the conversation
Rufnex Avatar

Nice Desktop! ;o)
Thank you for working on this topic!

2 Reply

What happened to Ryan's voice? You have a cold buddy?


Haha, I wish I could pull off a deep voice like this! We think Jesse sounds a bit like Sam Elliott, which is pretty cool 😎

Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
    "require": {
        "php": ">=8.1.0",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "symfony/asset": "6.1.*", // v6.1.0
        "symfony/console": "6.1.*", // v6.1.4
        "symfony/dotenv": "6.1.*", // v6.1.0
        "symfony/flex": "^2", // v2.2.3
        "symfony/framework-bundle": "6.1.*", // v6.1.4
        "symfony/http-client": "6.1.*", // v6.1.4
        "symfony/runtime": "6.1.*", // v6.1.3
        "symfony/twig-bundle": "6.1.*", // v6.1.1
        "symfony/yaml": "6.1.*" // v6.1.4
    "require-dev": {
        "phpunit/phpunit": "^9.5", // 9.5.23
        "symfony/browser-kit": "6.1.*", // v6.1.3
        "symfony/css-selector": "6.1.*", // v6.1.3
        "symfony/phpunit-bridge": "^6.1" // v6.1.3