9 grudnia 2019

Testy jednostkowe w PhpUnit (TDD)

Witam, warto czasem nasz kod przetestować (żartuję, starajcie się robić to zawsze).
Należy jednak wspomnieć, że testy to temat strasznie rozległy, potraktujmy ten wpis jako część pierwszą długiej serii 🙂

Nie lubię pisać wstępów (nie wychodzi mi to najlepiej), więc przejdę do konkretów.

Zaczynamy

Tworzymy katalog (w moim przypadku będzie to „TDD„).

Potrzebne narzędzia pracy

Potrzebować będziemy oczywiście PHP (najlepiej >7.2) oraz composer

W katalogu w którym chcemy rozpocząć prace, dajemy polecenie:

composer init

Po przejściu przez krótki i prosty formularz stworzony zostanie plik „composer.json„, jego zawartość wyglądać podobnie do poniższej:

{
    "name": "rdani/tdd",
    "description": "Tutorial dla ifcode.pl",
    "type": "project",
    "require": {},
    "require-dev": {}
}

W tym momencie plik „composer.json” został zmodyfikowany:

{
    "name": "rdani/tdd",
    "description": "Tutorial dla ifcode.pl",
    "type": "project",
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "require": {},
    "require-dev": {}
}

Dopiszmy do niego „autoloader„:

{
    "name": "rdani/tdd",
    "description": "Tutorial dla ifcode.pl",
    "type": "project",
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "require": {},
    "require-dev": {}
}

Teraz wystarczy wydać polecenie:

composer install

Możliwe problemy:

W trakcie pisania tego tutoriala napotkałem na kilka problemów.
Całość była uruchamiana w systemie Ubuntu z PHP 7.2

Treść błędu:

phpunit/phpunit 8.0.0 requires ext-mbstring * -> the requested PHP extension mbstring is missing from your system.

Rozwiązanie:

sudo apt-get install php-mbstring

Treść błędu:

Failed to download sebastian/version from dist: The zip extension and unzip command are both missing, skipping.
Your command-line PHP is using multiple ini files. Run `php --ini` to show them.
    Now trying to download from source

Rozwiązanie:

sudo apt-get install zip unzip php7.2-zip

Ściągamy plik PhpUnit

wget https://phar.phpunit.de/phpunit-8.2.phar

Zmieniamy uprawnienia pliku:

chmod +x phpunit-8.2.phar

Piszemy pierwszy test

Pamiętajcie, zaczynamy od testu. Napiszmy na początek najprostszy test.

Ustalamy, że będziemy testować funkcję która ma za zadanie przyjąć od nas jako parametr tablicę jednowymiarową, połączyć jej elementy i zwrócić w postaci string.

No więc coś już wiemy o działaniu funkcji, możemy napisać testy.

Na początek, powinniśmy stworzyć plik php wewnątrz katalogu „tests” i nazwać go odpowiednio.

Jak dobrać nazwę ? Jeśli testy odnoszą się do pliku o nazwie np: „Table„, wewnątrz którego jest klasa o takiej samej nazwie, wtedy test powinien zostać nazwany „TableTest„.

Zawartość początkowa pliku „tests/TableTest.php

<?php
declare(strict_types=1);

namespace Tests;

require 'vendor/autoload.php';

use PHPUnit\Framework\TestCase;
use App\Controller;

class TableTest extends TestCase
{

}

Dodajmy do naszego pliku pierwszą zmienną klasową oraz metodę „setUp„.

Metoda „setUp” pełni funkcję konstruktora, uruchamiana jest automatycznie po uruchomieniu testu.

Zawartość pliku „tests/TableTest.php

<?php
declare(strict_types=1);

namespace Tests;

require 'vendor/autoload.php';

use PHPUnit\Framework\TestCase;
use App\Controller;

class TableTest extends TestCase
{

    private $table;

    protected function setUp():void
    {
        $this->table = new Controller\Table();
    }
}

Po uruchomieniu testu:

php .\phpunit-8.2.5.phar tests

Otrzymamy:

1) Warning
No tests found in class "Tests\TableTest".

Zróbmy więc pierwszy test, w tym celu musimy wykonać metodę o przykładowej nazwie „testException„.

public function testException():void
{
    $this->expectException(\Exception::class);
    $this->table->set();
}

Wynik testu powinien być następujący:

1) Tests\TableTest::testException
Error: Call to undefined method App\Controller\Table::set()

Ale gdy metodę stworzymy i będzie się ona prezentować następująco:

public function set()
{
    throw new \Exception('Error :)', 100);
}

Test wypadnie pozytywnie:

OK (1 test, 1 assertion)

Podsumowanie

Pierwszy test mamy za sobą. W kolejnych wpisach postaram się wykonać więcej testów, aby pomóc lepiej poznać PhpUnit.