PHP Unit Testing with PHPUnit
Tests are the safety net that lets you refactor with confidence. PHPUnit is the standard testing framework for PHP. Well-tested code has fewer bugs, is easier to refactor, and signals professionalism in interviews and code reviews.
Installation and First Test
composer require --dev phpunit/phpunit
./vendor/bin/phpunit --version
<?php
// src/Calculator.php
class Calculator {
public function add(float $a, float $b): float { return $a + $b; }
public function divide(float $a, float $b): float {
if ($b === 0.0) throw new DivisionByZeroError("Cannot divide by zero");
return $a / $b;
}
}
// tests/CalculatorTest.php
use PHPUnit\Framework\TestCase;
class CalculatorTest extends TestCase {
private Calculator $calc;
protected function setUp(): void {
$this->calc = new Calculator();
}
public function test_add_two_positive_numbers(): void {
$result = $this->calc->add(2, 3);
$this->assertEquals(5, $result);
}
public function test_add_negative_numbers(): void {
$this->assertEquals(-1, $this->calc->add(-2, 1));
}
public function test_divide_throws_on_zero(): void {
$this->expectException(DivisionByZeroError::class);
$this->calc->divide(10, 0);
}
}
Assertions Reference
<?php
$this->assertEquals(expected, actual); // == equality
$this->assertSame(expected, actual); // === equality (strict)
$this->assertTrue(condition);
$this->assertFalse(condition);
$this->assertNull($value);
$this->assertNotNull($value);
$this->assertCount(3, $array);
$this->assertArrayHasKey('name', $array);
$this->assertStringContainsString('php', $str);
$this->assertInstanceOf(User::class, $obj);
Mocking Dependencies
<?php
class UserService {
public function __construct(private UserRepository $repo) {}
public function getActiveUser(int $id): ?array {
$user = $this->repo->findById($id);
return ($user && $user['active']) ? $user : null;
}
}
class UserServiceTest extends TestCase {
public function test_returns_null_for_inactive_user(): void {
// Mock the repository — don't hit real DB
$repo = $this->createMock(UserRepository::class);
$repo->method('findById')
->with(42)
->willReturn(['id' => 42, 'name' => 'Rahul', 'active' => false]);
$service = new UserService($repo);
$this->assertNull($service->getActiveUser(42));
}
}
Q: What is the difference between a unit test and an integration test?
A unit test tests a single class or function in isolation — all dependencies are mocked. Fast, reliable, no database. An integration test tests multiple components working together — real database, real file system. Slower but tests actual wiring. Both are needed: unit tests for logic, integration tests for components working together.
Comments (0)
No comments yet. Be the first!
Leave a Comment