7.9 KiB
Testing Guide for MineSeeker
MineSeeker-specific testing setup and workflows. For general PHPUnit/Symfony testing, see Symfony Testing Docs.
Example of the current tests
$ bin/phpunit (master->origin/master|✚1…2⚑1)
PHPUnit 13.1.7 by Sebastian Bergmann and contributors.
Runtime: PHP 8.5.5
Configuration: /var/www/splendid/Mine/phpunit.dist.xml
................................................................. 65 / 71 ( 91%)
...... 71 / 71 (100%)
Time: 00:07.319, Memory: 86.50 MB
OK (71 tests, 227 assertions)
Faker seed used: 918823
Quick Start
# One-time setup
make test-db-setup
# Run tests
make test
Test Database Configuration
MineSeeker uses a separate test database (mineseeker_test) with automatic transaction rollback for isolated tests.
Stack
- PHPUnit 13 - Testing framework
- Zenstruck Foundry - Factory library for test fixtures
- DAMA Doctrine Test Bundle - Transaction isolation (rollback after each test)
Configuration
phpunit.dist.xml:
<env name="DATABASE_URL" value="postgresql://...mineseeker_test..." />
<env name="DAMA_DISABLE_STATIC_CONNECTION" value="0" />
config/bundles.php:
Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true],
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
Setup
One-time Setup
make test-db-setup
Creates mineseeker_test database and runs migrations.
Reset Test Database
make test-db-reset
Drops and recreates test database (useful after schema changes).
Running Tests
# All tests
make test
# Specific file
vendor/bin/phpunit tests/Controller/ProfileControllerTest.php
# Specific method
vendor/bin/phpunit --filter testCreateUser
# With test names
vendor/bin/phpunit --testdox
MineSeeker Factories
See FACTORIES.md for complete factory API.
Available Factories
| Factory | Entity | Location |
|---|---|---|
UserFactory |
Registered users | tests/Factory/UserFactory.php |
GamerFactory |
Anonymous players | tests/Factory/GamerFactory.php |
PlayedGameFactory |
Game records | tests/Factory/PlayedGameFactory.php |
StepFactory |
Game moves | tests/Factory/StepFactory.php |
GridFactory |
16×16 game grids | tests/Factory/GridFactory.php |
GridRowFactory |
Grid rows | tests/Factory/GridRowFactory.php |
WebAuthnCredentialFactory |
Passkey credentials | tests/Factory/WebAuthnCredentialFactory.php |
ContactMessageFactory |
Contact messages | tests/Factory/ContactMessageFactory.php |
Example
use App\Tests\Factory\PlayedGameFactory;
use App\Tests\WebTestCase;
class GameTest extends WebTestCase
{
public function testGameCreation(): void
{
$game = PlayedGameFactory::new()
->withRegisteredPlayers()
->redWins()
->create();
self::assertEquals(26, $game->redPoints);
}
}
Test Structure
All tests extend App\Tests\WebTestCase:
<?php declare(strict_types=1);
/**
* This file is part of the SplendidBear Websites' projects.
*
* Copyright (c) 2026 @ www.splendidbear.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Tests\Controller;
use App\Tests\Factory\UserFactory;
use App\Tests\WebTestCase;
class MyControllerTest extends WebTestCase
{
public function testExample(): void
{
$user = UserFactory::createOne();
$client = static::createClient();
$client->request('GET', '/profile');
self::assertResponseRedirects('/login');
}
}
Important: Always extend App\Tests\WebTestCase, not Symfony\Bundle\FrameworkBundle\Test\WebTestCase.
Directory Structure
tests/
├── Controller/ # HTTP endpoint tests
├── Dto/ # Data Transfer Object tests
├── Entity/ # Entity logic tests
├── Service/ # Service layer tests
├── Integration/ # Integration tests
├── Factory/ # Foundry factories
├── WebTestCase.php # Base test class
└── bootstrap.php # PHPUnit bootstrap
MineSeeker-Specific Patterns
Testing Game Flow
public function testRedPlayerWinsGame(): void
{
$game = PlayedGameFactory::new()
->withRegisteredPlayers()
->create();
// Create steps to simulate gameplay
for ($i = 0; $i < 26; $i++) {
StepFactory::new()
->forPlayer('red')
->mine()
->create(['playedGame' => $game]);
}
self::assertEquals(26, $game->redPoints);
}
Testing Battle Sharing
public function testBattleSharePageReturnsValidGame(): void
{
$game = PlayedGameFactory::new()
->withRegisteredPlayers()
->redWins()
->create();
$client = static::createClient();
$client->request('GET', '/battle/' . $game->uuid);
self::assertResponseIsSuccessful();
self::assertSelectorTextContains('h1', 'Battle Report');
}
Testing Authentication
public function testProfileRequiresAuthentication(): void
{
$client = static::createClient();
$client->request('GET', '/profile');
self::assertResponseRedirects('/login');
}
public function testAuthenticatedUserCanAccessProfile(): void
{
$user = UserFactory::createOne();
$client = static::createClient();
$client->loginUser($user->_real());
$client->request('GET', '/profile');
self::assertResponseIsSuccessful();
}
Troubleshooting
Tests interfering with each other?
Ensure you extend App\Tests\WebTestCase, not the base Symfony class.
Schema out of sync?
make test-db-reset
Memory limit errors?
php -d memory_limit=1024M vendor/bin/phpunit
Or increase in phpunit.dist.xml:
<ini name="memory_limit" value="1024M"/>
Test database doesn't exist?
make test-db-setup
External Resources
- Symfony Testing - Symfony testing guide
- Zenstruck Foundry - Factory documentation
- DAMA Doctrine Test Bundle - Transaction isolation
- PHPUnit - PHPUnit documentation
Modern PHPUnit Attributes
MineSeeker tests use modern PHP 8 attributes instead of method name prefixes:
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\Attributes\TestDox;
#[TestDox('Security Controller')]
class SecurityControllerTest extends WebTestCase
{
#[Test]
#[TestDox('Login page loads successfully with form fields')]
public function loginPageLoadsSuccessfully(): void
{
// Test implementation
}
}
Benefits:
- ✅ More readable method names (no
testprefix required) - ✅ Self-documenting with
TestDoxdescriptions - ✅ Better IDE support and refactoring
- ✅ Cleaner
--testdoxoutput
Run with documentation:
vendor/bin/phpunit --testdox
Output:
Security Controller
✔ Login page loads successfully with form fields
✔ Login page has links to register and forgot password
✔ Register page loads successfully with form