Testing An App
Tests protect your application code while CorianderCore can update independently.
What To Test First
Start with the behavior that would hurt if it broke:
- route smoke tests
- repository methods
- permission services
- validation rules
- Markdown/documentation links, for documentation sites
- generated downloads, for guided projects
Module Unit Test
Modules are the easiest app code to test because they should not depend on HTTP rendering.
use App\Modules\Blog\BlogValidator;
use PHPUnit\Framework\TestCase;
final class BlogValidatorTest extends TestCase
{
public function testTitleIsRequired(): void
{
$errors = (new BlogValidator())->validatePost([
'title' => '',
'body' => 'Content',
]);
self::assertArrayHasKey('title', $errors);
}
}
Route Smoke Test
Smoke tests check that important public routes still respond after framework updates.
public function testDocumentationRouteResponds(): void
{
$request = new \Nyholm\Psr7\ServerRequest('GET', '/documentation');
$response = (new \CorianderCore\Core\Router\Router())->handle($request);
self::assertSame(200, $response->getStatusCode());
self::assertStringContainsString('Documentation', (string) $response->getBody());
}
Prefer focused route smoke tests over browser-heavy tests for basic coverage.
Bootstrap the test's environment, configuration, and autoloaders first. Use an isolated test database and session storage, never your production database. The router test exercises middleware and handlers, not the front controller's parsing or HTTP emission; add an HTTP check for those boundaries.
For JSON integration requests, use RequestFactory::fromGlobals() or set withParsedBody($payload) on a constructed PSR request. Cookie-authenticated writes need a valid csrf_token body field; do not disable root middleware in a permission test.
Repository Tests
For repository code, use a test database when possible.
SQLite is practical for fast local tests. If production uses MySQL-specific SQL, add at least one integration check against MySQL before release.
Permission Tests
Permission services should be deterministic.
public function testAdminCanEditAnyPost(): void
{
$service = new BlogPermissionService();
self::assertTrue($service->canEdit(
['id' => 1, 'role' => 'admin'],
['author_id' => 99]
));
}
Test permission rules once in the permission class, then keep handler tests lighter.
Documentation App Checks
For documentation websites, add quality checks:
- internal links exist
- code fence languages are supported
- downloads exist
- generated assets exist
- no app code lives under
CorianderCore
This documentation site uses that pattern in tests/Docs.
Before Merging
Run:
composer test
php coriander nodejs run build-prod
When downloads or assets changed, also run:
composer generate-downloads
php coriander nodejs run build-prod