DEV Community

Eelco Verbrugge
Eelco Verbrugge

Posted on

Symfony Unit Testing

In order to unit test in Symfony, we need to install symfony's test-pack first:

$ composer require --dev symfony/test-pack
Enter fullscreen mode Exit fullscreen mode

Check if install succeed by running PHPUnit:

$ php bin/phpunit
Enter fullscreen mode Exit fullscreen mode

If you are running your project in a docker container, make sure you run this command in your container.

$ docker exec -it [enter_container_name] php bin/phpunit
Enter fullscreen mode Exit fullscreen mode

If everything went well, you should receive the message "No tests executed!"

Write your first test

Create your first test "FirstTest.php" and place it in the directory "tests" of the root of your project:

<?php

namespace Api\Tests;

use PHPUnit\Framework\TestCase;

class FirstTest extends TestCase
{
    public function testEquals() {
        $actual = 1;
        $expected = 1;

        $this->assertEquals($expected, $actual);
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see this class extends from TestCase, which is needed to initiate a PHPUnit test. In this test we test if the $actual and $expected are equals.

Now try and run this test to see what happens:

$ php bin/phpunit
Enter fullscreen mode Exit fullscreen mode

The result should be something like "OK (1 test, 1 assertion)"

Congrats! You just wrote your very first PHPUnit test.

What to test?

This is great, but how can I apply this to my code? Great question, lets check this out.

Firstly, we'll create a controller so we can test the outcome of our method:

<?php

namespace Api\Controller;

class Calculator
{
    public function add ($a, $b) {
        return $a + $b;
    }
}
Enter fullscreen mode Exit fullscreen mode

The naming convention for a test exists of "Controller + Test" used in CamelCase. So ours will be CalculatorTest. The method itself exist of "test + Method". Like so:

<?php

namespace Api\Tests;

use Api\Controller\Calculator;
use PHPUnit\Framework\TestCase;

class CalculatorTest extends TestCase
{
    public function testAdd() {
        $calculator = new Calculator();
        $actual = $calculator->add(1,2);

        $expected = 3;

        $this->assertEquals($expected, $actual);
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see, we've initiated a Calculator object and added the numbers 1 and 2 as $actual result. My $expected result is an outcome of 3. If we run this test $ php bin/phpunit we'll see our test runs successfully "OK (1 test, 1 assertion)".

Why to test

Now lets say after a couple of months your colleague gets the question to change your method because of whatever reason. He or she changed it to always add +10:

<?php

namespace Api\Controller;

class Calculator
{
    public function add ($a) {
        return $a + 10;
    }
}
Enter fullscreen mode Exit fullscreen mode

If we run our test again now $ php bin/phpunit, we'll get exactly what we want. An error:

"FAILURES! Tests: 1, Assertions: 1, Failures: 1.".

So our colleague knows he changed something what shouldn't be changed or he needs to refactor our test and probably more code elsewhere.

Bonus

If you write tests before you write the actual code itself, this would be a great practice for Test Driven Development (TDD). A great way to think before coding and ensure the quality of your code.

Couple of asserts I like to use are:

  1. $this->assertEquals($expected, $actual);
  2. $this->assertTrue($argument);
  3. $this->assertInstanceOf(Object::class, $object);
  4. $this->assertSame($expected, $actual);
  5. $this->assertFalse($argument);

Hope this helps!

Top comments (2)

Collapse
 
detzam profile image
webstuff

sooo basically test, unittests are for some features that are discussed to work in a way that remains fixed throughout the app. And they make it so you knowif chnages ruin these preset things.

Am i in the ball paark or not?
i;m asking because i;ve been wanting to do this but i didn;t know how its done and i don;t have people that do TDD sadly

Collapse
 
eelcoverbrugge profile image
Eelco Verbrugge

I use it to make sure I don’t break something when I’m fixing a bug or adding features. TDD is just a different approach, it makes you think first about the minimal requirements of the feature and program after. In my experience a lot of people talk about it but don’t really use it. So I will try by myself and share my thoughts