PHP 8: Modern PHP Development · Testing and Tooling

Unit Testing with PHPUnit

Write fast, focused tests with PHPUnit 11 attributes and data providers.

PHPUnit is the standard PHP test framework (Pest builds a friendlier syntax on top). Tests extend TestCase, use assertions like assertSame(), and since PHPUnit 10/11 use attributes (#[Test], #[DataProvider], #[CoversClass]) instead of docblock annotations. Follow Arrange-Act-Assert, test behavior through public methods, and use data providers for tables of cases.

<?php
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class MoneyTest extends TestCase
{
    #[Test]
    public function it_adds_amounts_in_the_same_currency(): void
    {
        $total = (new Money(1000, 'USD'))->add(new Money(250, 'USD'));
        $this->assertSame(1250, $total->amount);
    }

    #[Test]
    public function it_rejects_currency_mismatch(): void
    {
        $this->expectException(LogicException::class);
        (new Money(1, 'USD'))->add(new Money(1, 'EUR'));
    }

    public static function invalidAmounts(): iterable
    {
        yield 'negative' => [-1];
        yield 'very negative' => [-1000];
    }

    #[Test, DataProvider('invalidAmounts')]
    public function it_rejects_negative_amounts(int $amount): void
    {
        $this->expectException(InvalidArgumentException::class);
        new Money($amount, 'USD');
    }
}

Common pitfalls

  • Using assertEquals where assertSame is meant (loose comparison).
  • Data providers must be public static in PHPUnit 10+.
  • Testing private methods directly instead of behavior.

Key points

  • assertSame for strict checks
  • Attributes replace annotations
  • Data providers for case tables

Further reading: PHPUnit documentation

Practice questions

What's the difference between assertSame() and assertEquals()?

Answer

assertSame uses strict identity (===, same type and value or same object instance); assertEquals uses loose comparison, so '1' equals 1. Prefer assertSame for scalars.

Why use data providers?

Answer

They run the same test logic against many inputs, each reported separately by name, reducing duplication while keeping failures clear.

Open in the app to mark lessons complete, take notes and track your progress.