PHPUnit Testing Best Practices
PHPUnit Testing Best Practices in XOOPS
Section titled “PHPUnit Testing Best Practices in XOOPS”Testing is essential for ensuring code quality, preventing regressions, and enabling confident refactoring.
Installing PHPUnit
Section titled “Installing PHPUnit”# Using Composercomposer require --dev phpunit/phpunit ^9.0
# Run tests./vendor/bin/phpunitphpunit.xml Configuration
Section titled “phpunit.xml Configuration”<?xml version="1.0" encoding="UTF-8"?><phpunit bootstrap="tests/bootstrap.php" colors="true" verbose="true"> <testsuites> <testsuite name="Unit"> <directory>tests/unit</directory> </testsuite> <testsuite name="Integration"> <directory>tests/integration</directory> </testsuite> </testsuites>
<coverage processUncoveredFiles="true"> <include> <directory suffix=".php">class</directory> </include> <report> <html outputDirectory="coverage"/> </report> </coverage></phpunit>Writing Unit Tests
Section titled “Writing Unit Tests”<?phpnamespace Xoops\Module\Mymodule\Tests\Unit;
use PHPUnit\Framework\TestCase;use Xoops\Module\Mymodule\Service\UserService;
class UserServiceTest extends TestCase{ private $userService; private $mockRepository;
protected function setUp(): void { parent::setUp(); $this->mockRepository = $this->createMock( \Xoops\Module\Mymodule\Repository\UserRepositoryInterface::class ); $this->userService = new UserService($this->mockRepository); }
public function testRegisterSuccess() { // Arrange $this->mockRepository->expects($this->once()) ->method('findByUsername') ->willReturn(null);
$this->mockRepository->expects($this->once()) ->method('save') ->willReturn(1);
// Act $result = $this->userService->register('user', 'test@test.com', 'pass');
// Assert $this->assertNotNull($result); }
public function testRegisterDuplicate() { // Arrange $existingUser = new \stdClass(); $this->mockRepository->expects($this->once()) ->method('findByUsername') ->willReturn($existingUser);
// Act & Assert $this->expectException(\Exception::class); $this->userService->register('user', 'test@test.com', 'pass'); }}?>Testing Data Objects
Section titled “Testing Data Objects”<?phpclass UserDTOTest extends TestCase{ public function testDTOCreation() { $user = new User(); $user->setId(1) ->setUsername('testuser') ->setEmail('test@test.com');
$dto = new UserDTO($user);
$this->assertEquals(1, $dto->getId()); $this->assertEquals('testuser', $dto->getUsername()); }
public function testDTOToArray() { $user = new User(); $user->setId(1)->setUsername('testuser');
$dto = new UserDTO($user); $array = $dto->toArray();
$this->assertIsArray($array); $this->assertEquals(1, $array['id']); }}?>Code Coverage
Section titled “Code Coverage”# Generate coverage report./vendor/bin/phpunit --coverage-html coverage
# View coverage percentage./vendor/bin/phpunit --coverage-textBest Practices
Section titled “Best Practices”- Write one test per method/scenario
- Use descriptive test names
- Follow Arrange-Act-Assert pattern
- Mock external dependencies
- Keep tests focused and independent
- Aim for 80%+ code coverage
- Test error conditions
- Test boundary cases
Test Organization
Section titled “Test Organization”tests/├── unit/│ ├── UserServiceTest.php│ ├── UserRepositoryTest.php│ └── UserDTOTest.php├── integration/│ ├── UserControllerTest.php│ └── UserServiceTest.php├── fixtures/│ └── users.php├── bootstrap.php└── phpunit.xmlRelated Documentation
Section titled “Related Documentation”See also:
- Error-Handling for exception testing
- ../Patterns/Repository-Pattern for repository testing
- ../Patterns/Service-Layer for service testing
- Code-Organization for test structure
Tags: #best-practices #testing #phpunit #code-coverage #module-development