Skip to content

Testing

Technomantus Corvi edited this page Sep 5, 2026 · 1 revision

Testing

Installing PHP from scratch (Ubuntu/Mint)

sudo apt update
sudo apt install php8.1 php8.1-cli php8.1-mysql php8.1-xml php8.1-mbstring php8.1-curl php8.1-zip unzip
Package Why
php8.1-mysql PDO driver (Database::connect())
php8.1-xml dom/xmlwriter, required by PHPUnit reports
php8.1-mbstring, php8.1-curl, php8.1-zip Required by Composer

Use php8.1-pgsql instead of/alongside php8.1-mysql for PostgreSQL.

Installing Composer

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

Installing PHPUnit

PHP 8.1 requires PHPUnit 10.x (11+ drops 8.1 support):

composer init --name="your-username/tanuki-base" --type=project --no-interaction
composer require --dev "phpunit/phpunit:^10.5"

Configuration

phpunit.xml:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php" colors="true">
    <testsuites>
        <testsuite name="Unit"><directory>tests/Unit</directory></testsuite>
        <testsuite name="Feature"><directory>tests/Feature</directory></testsuite>
    </testsuites>
</phpunit>

tests/bootstrap.php:

<?php
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/../utils.php';
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../core/Model.php';
require_once __DIR__ . '/../core/Request.php';
require_once __DIR__ . '/../core/Controller.php';

$envFile = file_exists(__DIR__ . '/../.env.testing')
    ? __DIR__ . '/../.env.testing'
    : __DIR__ . '/../.env';

if (file_exists($envFile)) {
    foreach (file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line) {
        $line = trim($line);
        if ($line === '' || $line[0] === '#' || !str_contains($line, '=')) continue;
        [$key, $value] = explode('=', $line, 2);
        $_ENV[trim($key)] = trim($value, " \t\"'");
    }
}

.env.testing (never commit — points to a throwaway database):

APP_ENV=testing
DB_DRIVER=mysql
DB_HOST=localhost
DB_NAME=tanuki_db
DB_USER=your_test_user
DB_PASS=your_test_password

Consider DB_DRIVER=sqlite here instead — no running service needed, which simplifies CI a lot.

Running tests

./vendor/bin/phpunit                          # everything
./vendor/bin/phpunit --testsuite Unit         # no database required
./vendor/bin/phpunit --testsuite Feature      # requires the test DB
./vendor/bin/phpunit tests/Feature/TodoModelTest.php

Test suite conventions

  • Unit tests never touch a database. Feature tests hit the real (test) database.
  • setUp() clears the relevant table before each test for isolation; consider beginTransaction()/rollBack() as the suite grows.
  • Add a regression test for every subtle bug you fix — the framework's own suite includes tests for the env() falsy-value bug and the column-name SQL injection fix as examples of this pattern.

Clone this wiki locally