PHP / PHPUnit тест бичих

PHPUnit тест бичих

Код бичсэний дараа "ажиллаж байна уу?" гэдгийг гараар шалгах нь уйтгартай, найдваргүй. PHPUnit нь PHP-ийн стандарт тест фреймворк бөгөөд таны функц, класс зөв ажиллаж байгааг автоматаар, секундэд шалгадаг. Тест бичих нь "нэмэлт ажил" биш — кодоо илүү итгэлтэй, өөрчилж болохуйц болгодог.

PHPUnit суулгах

bash
# Composer-ээр суулгана (development dependency)
composer require --dev phpunit/phpunit

# Суулгасан эсэхийг шалгах
./vendor/bin/phpunit --version
# PHPUnit 11.x.x by Sebastian Bergmann ...

# Товч тушаал (composer.json-д нэмж болно)
# "scripts": { "test": "phpunit" }
# composer test

phpunit.xml тохируулгын файл үүсгэнэ:

xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true">
    <testsuites>
        <testsuite name="Unit">
            <directory>tests/Unit</directory>
        </testsuite>
    </testsuites>
    <source>
        <include>
            <directory>src</directory>
        </include>
    </source>
</phpunit>

Анхны тест бичих

Тест нь TestCase-г өвлөсөн класс, test-ээр эхэлсэн методуудаас бүрдэнэ:

php
<?php
// tests/Unit/CalculatorTest.php
namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use App\Calculator;

class CalculatorTest extends TestCase
{
    // Тест метод нэр test-ээр эхэлнэ
    public function test_нэмэх_зөв_үр_дүн_өгнө(): void
    {
        $calc = new Calculator();

        $үр_дүн = $calc->нэмэх(3, 5);

        $this->assertEquals(8, $үр_дүн);
    }

    public function test_хуваахад_тэгд_хуваавал_exception_гарна(): void
    {
        $calc = new Calculator();

        $this->expectException(\DivisionByZeroError::class);

        $calc->хуваах(10, 0);
    }

    public function test_квадрат_язгуур_зөв(): void
    {
        $calc = new Calculator();

        $this->assertEquals(4.0,  $calc->язгуур(16));
        $this->assertEquals(3.0,  $calc->язгуур(9));
        $this->assertEqualsWithDelta(1.414, $calc->язгуур(2), 0.001);
    }
}
php
<?php
// src/Calculator.php
namespace App;

class Calculator
{
    public function нэмэх(float $a, float $b): float
    {
        return $a + $b;
    }

    public function хуваах(float $a, float $b): float
    {
        if ($b === 0.0) {
            throw new \DivisionByZeroError("Тэгд хуваах боломжгүй.");
        }
        return $a / $b;
    }

    public function язгуур(float $тоо): float
    {
        return sqrt($тоо);
    }
}
?>

Тестийг ажиллуулна:

bash
./vendor/bin/phpunit

# PHPUnit 11.x.x
# ........                                    3 / 3 (100%)
# OK (3 tests, 4 assertions)

Assert методууд — шалгах аргууд

PHPUnit олон assert методтой. Хамгийн их хэрэглэгддэгүүд:

php
<?php
use PHPUnit\Framework\TestCase;

class AssertJisheeTest extends TestCase
{
    public function test_assert_методуудын_жишээ(): void
    {
        // Тэнцүү эсэх (loose)
        $this->assertEquals(42, "42");          // ✓ loose

        // Яг тэнцүү (strict — төрөл ч таарах ёстой)
        $this->assertSame(42, 42);              // ✓
        // $this->assertSame(42, "42");         // ✗ алдаа — int vs string

        // Үнэн/худал
        $this->assertTrue(5 > 3);
        $this->assertFalse(empty("PHP"));

        // null шалгах
        $this->assertNull(null);
        $this->assertNotNull("утга");

        // Массив
        $this->assertCount(3, [1, 2, 3]);
        $this->assertContains("PHP", ["PHP", "Go"]);
        $this->assertArrayHasKey("нэр", ["нэр" => "Дорж"]);

        // Мөр
        $this->assertStringContainsString("PHP", "PHP бол хэл");
        $this->assertStringStartsWith("PHP", "PHP is great");
        $this->assertStringEndsWith("хэл", "PHP бол хэл");

        // Тоо
        $this->assertGreaterThan(3, 5);
        $this->assertLessThanOrEqual(10, 10);
        $this->assertEqualsWithDelta(3.14, M_PI, 0.01);

        // Exception
        $this->expectException(\InvalidArgumentException::class);
        $this->expectExceptionMessage("Буруу оролт");
        throw new \InvalidArgumentException("Буруу оролт");
    }
}
?>

Практик жишээ — UserService тест

Бодит ажлын тест иймэрхүү харагдана:

php
<?php
// src/Services/UserService.php
namespace App\Services;

class UserService
{
    public function имэйл_шалгах(string $имэйл): bool
    {
        return (bool) filter_var($имэйл, FILTER_VALIDATE_EMAIL);
    }

    public function нууц_үг_хүч(string $нууц_үг): string
    {
        $оноо = 0;
        if (strlen($нууц_үг) >= 8)          $оноо++;
        if (preg_match('/[A-Z]/', $нууц_үг)) $оноо++;
        if (preg_match('/[0-9]/', $нууц_үг)) $оноо++;
        if (preg_match('/[\W]/',  $нууц_үг)) $оноо++;

        return match(true) {
            $оноо <= 1 => 'сул',
            $оноо <= 2 => 'дунд',
            $оноо <= 3 => 'сайн',
            default    => 'маш сайн',
        };
    }
}
php
<?php
// tests/Unit/UserServiceTest.php
namespace Tests\Unit;

use PHPUnit\Framework\TestCase;
use App\Services\UserService;

class UserServiceTest extends TestCase
{
    private UserService $service;

    // Тест бүрийн өмнө ажиллана
    protected function setUp(): void
    {
        $this->service = new UserService();
    }

    // Data provider — нэг тестийг олон өгөгдлөөр ажиллуулна
    public static function имэйл_өгөгдөл(): array
    {
        return [
            'зөв имэйл'             => ['user@example.mn', true],
            'зөв имэйл + subdomain' => ['a@b.co.mn',       true],
            '@-гүй'                 => ['userexample.mn',  false],
            'домэйнгүй'             => ['user@',           false],
            'хоосон мөр'            => ['',                false],
        ];
    }

    /** @dataProvider имэйл_өгөгдөл */
    public function test_имэйл_шалгалт(string $имэйл, bool $хүлээгдэж_байгаа): void
    {
        $this->assertSame($хүлээгдэж_байгаа, $this->service->имэйл_шалгах($имэйл));
    }

    public function test_нууц_үгийн_хүч_зэрэглэл(): void
    {
        $this->assertSame('сул',      $this->service->нууц_үг_хүч('abc'));
        $this->assertSame('дунд',     $this->service->нууц_үг_хүч('abcdefgh'));
        $this->assertSame('сайн',     $this->service->нууц_үг_хүч('Abcdefgh1'));
        $this->assertSame('маш сайн', $this->service->нууц_үг_хүч('Abcdefg1!'));
    }
}
?>
bash
./vendor/bin/phpunit --testdox

# UserService
#  ✓ Имэйл шалгалт зөв имэйл
#  ✓ Имэйл шалгалт зөв имэйл + subdomain
#  ✓ Имэйл шалгалт @-гүй
#  ✓ Нууц үгийн хүч зэрэглэл
# OK (6 tests, 8 assertions)

Дараагийн хичээлд:

Laravel фреймворкийн үндсүүдийг судална. Laravel яагаад PHP хөгжүүлэлтийг хурдасгадаг, MVC загвар хэрхэн ажилладаг, route, controller, view, Eloquent ORM хэрхэн эхэлж ажиллахыг үзнэ.