337 lines
7.9 KiB
Markdown
337 lines
7.9 KiB
Markdown
# Testing Guide for MineSeeker
|
||
|
||
MineSeeker-specific testing setup and workflows. For general PHPUnit/Symfony testing, see [Symfony Testing Docs](https://symfony.com/doc/current/testing.html).
|
||
|
||
## Example of the current tests
|
||
|
||
```shell
|
||
$ 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
|
||
|
||
```bash
|
||
# 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](https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html)** - Factory library for test fixtures
|
||
- **[DAMA Doctrine Test Bundle](https://github.com/dmaicher/doctrine-test-bundle)** - Transaction isolation (rollback after each test)
|
||
|
||
### Configuration
|
||
|
||
**`phpunit.dist.xml`**:
|
||
```xml
|
||
<env name="DATABASE_URL" value="postgresql://...mineseeker_test..." />
|
||
<env name="DAMA_DISABLE_STATIC_CONNECTION" value="0" />
|
||
```
|
||
|
||
**`config/bundles.php`**:
|
||
```php
|
||
Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true],
|
||
DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true],
|
||
```
|
||
|
||
---
|
||
|
||
## Setup
|
||
|
||
### One-time Setup
|
||
|
||
```bash
|
||
make test-db-setup
|
||
```
|
||
|
||
Creates `mineseeker_test` database and runs migrations.
|
||
|
||
### Reset Test Database
|
||
|
||
```bash
|
||
make test-db-reset
|
||
```
|
||
|
||
Drops and recreates test database (useful after schema changes).
|
||
|
||
---
|
||
|
||
## Running Tests
|
||
|
||
```bash
|
||
# 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](./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
|
||
|
||
```php
|
||
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
|
||
<?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
|
||
|
||
```php
|
||
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
|
||
|
||
```php
|
||
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
|
||
|
||
```php
|
||
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?
|
||
|
||
```bash
|
||
make test-db-reset
|
||
```
|
||
|
||
### Memory limit errors?
|
||
|
||
```bash
|
||
php -d memory_limit=1024M vendor/bin/phpunit
|
||
```
|
||
|
||
Or increase in `phpunit.dist.xml`:
|
||
```xml
|
||
<ini name="memory_limit" value="1024M"/>
|
||
```
|
||
|
||
### Test database doesn't exist?
|
||
|
||
```bash
|
||
make test-db-setup
|
||
```
|
||
|
||
---
|
||
|
||
## External Resources
|
||
|
||
- **[Symfony Testing](https://symfony.com/doc/current/testing.html)** - Symfony testing guide
|
||
- **[Zenstruck Foundry](https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html)** - Factory documentation
|
||
- **[DAMA Doctrine Test Bundle](https://github.com/dmaicher/doctrine-test-bundle)** - Transaction isolation
|
||
- **[PHPUnit](https://docs.phpunit.de/)** - PHPUnit documentation
|
||
|
||
---
|
||
|
||
## Modern PHPUnit Attributes
|
||
|
||
MineSeeker tests use modern PHP 8 attributes instead of method name prefixes:
|
||
|
||
```php
|
||
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 `test` prefix required)
|
||
- ✅ Self-documenting with `TestDox` descriptions
|
||
- ✅ Better IDE support and refactoring
|
||
- ✅ Cleaner `--testdox` output
|
||
|
||
**Run with documentation:**
|
||
```bash
|
||
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
|
||
```
|