Testing¶
The QA pipeline ships in M2-B. Every PR runs:
| Check | Tool | Scope |
|---|---|---|
| PHP syntax | php -l |
every *.php outside vendor/ and extention/TCPDF/ |
| Code style | php-cs-fixer |
src/, tests/, the three M1 utility rewrites |
| Static analysis | phpstan (level 6) |
same as code style |
| Unit tests | phpunit |
tests/Unit/** on PHP 8.2 + 8.3 |
Legacy directories (auth/, item/, framework/, repository/, …) are deliberately excluded from the lint/analyse scope — they migrate to src/ across M3-M4 and will be re-included with strict types in tow.
Running locally¶
# Inside the dev container (preferred):
make qa # cs-check + analyse + test
make test # unit suite only
make analyse # PHPStan
make cs-check # dry-run formatter
# On the host (requires `composer install`):
composer test
composer analyse
composer cs:check
composer cs:fix
Suites¶
tests/
├── bootstrap.php registers the legacy `saso\` autoloader
├── Unit/ pure functions / no I/O
├── Integration/ uses real MariaDB (created when M3 lands)
└── Feature/ end-to-end via Playwright (planned for M5)
What we test today (M2-B baseline — 52 cases)¶
Eithermonad —of,left,fromNullablequirks,map/flatMappropagation,filter,getOrElseThrow,orElse.Member— Argon2id format & non-determinism, verifyPassword for both modern and legacy hashes,needsRehashtruth table,idConstraint,passwordConstraint.CSRFtoken— 64-hex-char generation, intra-session stability,rotate(),hash_equalsverify, post-rotate rejection.EnvLoader— KEY=VALUE parsing, comments, single/double quote stripping, malformed-key rejection,getenv()precedence, default fallback, empty-vs-unset distinction.UploadValidator— pre-is_uploaded_filechecks. Post-SAPI flow (finfo_file,getimagesize) waits for the integration suite in M5.
Coverage targets¶
- Domain: ≥ 80%
- Application: ≥ 60%
- Overall: ≥ 50%
These ratchets are advisory until M3 publishes the first ADR formalizing them.
Writing new tests¶
<?php
declare(strict_types=1);
namespace Saso\Tests\Unit\YourNamespace;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
#[CoversClass(\Saso\YourNamespace\YourClass::class)]
final class YourClassTest extends TestCase
{
public function testItDoesTheThing(): void
{
// Arrange / Act / Assert
self::assertTrue(true);
}
}
Conventions:
- One test class per production class (
#[CoversClass]). - Method names start with
test.itandshouldstyles are also fine. - Prefer
self::assertSameoverself::assertEquals(strict equality). - Mocking the database is not allowed for integration / feature suites — see ADR 0007 (planned) for the reasoning.