On this page
PHPUnit Testing
Why Test?
Automated tests catch regressions, document behavior, and enable confident refactoring. PHPUnit is the standard testing framework for PHP.
Installation
composer require --dev phpunit/phpunit
./vendor/bin/phpunit --version
Your First Test
// tests/CalculatorTest.php
use PHPUnit\Framework\TestCase;
class CalculatorTest extends TestCase
{
public function testAddition(): void
{
$calc = new Calculator();
$this->assertEquals(4, $calc->add(2, 2));
}
}
Run tests:
./vendor/bin/phpunit
Assertions
$this->assertTrue($condition);
$this->assertFalse($condition);
$this->assertEquals('expected', $actual);
$this->assertSame(42, $value); // strict (===)
$this->assertCount(3, $array);
$this->assertStringContainsString('foo', $haystack);
$this->assertInstanceOf(User::class, $obj);
$this->expectException(InvalidArgumentException::class);
Data Providers
Test multiple inputs without duplicating methods:
/**
* @dataProvider additionProvider
*/
public function testAdd(int $a, int $b, int $expected): void
{
$this->assertEquals($expected, (new Calculator())->add($a, $b));
}
public static function additionProvider(): array
{
return [
[1, 1, 2],
[0, 0, 0],
[-1, 1, 0],
];
}
Mocking Dependencies
public function testSendWelcomeEmail(): void
{
$mailer = $this->createMock(MailerInterface::class);
$mailer->expects($this->once())
->method('send')
->with($this->stringContains('Welcome'));
$service = new UserService($mailer);
$service->register('[email protected]');
}
Testing HTTP (Laravel)
public function testHomePageReturns200(): void
{
$response = $this->get('/');
$response->assertStatus(200);
$response->assertSee('Welcome');
}
Configuration
phpunit.xml:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php" colors="true">
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
</testsuites>
</phpunit>
Best Practices
- Arrange-Act-Assert structure in each test
- One logical assertion per test when possible
- Name tests descriptively:
testUserCannotLoginWithWrongPassword - Run tests in CI on every pull request
- Aim for high coverage on business logic; don’t chase 100% on trivial code
Testing is a hallmark of professional PHP development — start early and test often.