# Testing Patterns

**Analysis Date:** 2026-04-21

## Test Framework

**Runner:**
- PHPUnit exists in the project only as part of the ThinkPHP framework (`thinkphp/phpunit.xml`)
- No project-level test runner configured

**Assertion Library:**
- PHPUnit's built-in assertions (only in framework's own tests)

**No Project Tests Exist.** After thorough exploration of the entire codebase:

- `application/**/*.test.php` -- None found
- `application/**/*.spec.php` -- None found
- `tests/` directory -- Does not exist at project root
- `phpunit.xml` -- Only exists at `thinkphp/phpunit.xml` (framework's own test suite)
- `.idea/phpunit.xml` -- IDE config pointing to `thinkphp/phpunit.xml` (for framework testing only)

**Framework PHPUnit Config (`thinkphp/phpunit.xml`):**
```xml
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="tests/mock.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="false">
    <testsuites>
        <testsuite name="ThinkPHP Test Suite">
            <directory>./tests/thinkphp/</directory>
        </testsuite>
    </testsuites>
    <listeners>
        <listener class="JohnKary\PHPUnit\Listener\SpeedTrapListener" />
    </listeners>
    <filter>
        <whitelist>
            <directory suffix=".php">./</directory>
            <exclude>
                <directory suffix=".php">tests</directory>
                <directory suffix=".php">vendor</directory>
            </exclude>
        </whitelist>
    </filter>
</phpunit>
```
This config is for testing the ThinkPHP framework itself, NOT the application code in `application/`.

**ThinkPHP Framework Tests (not application code):**
- `thinkphp/tests/` contains ~50 test files testing framework internals
- Covers: Cache, Config, Controller, DB, Debug, Exception, Hook, Lang, Loader, Log, Model, Paginate, Request, Response, Route, Session, Template, URL, Validate, View
- Example: `thinkphp/tests/thinkphp/library/think/validateTest.php`

**Vendor Tests (not application code):**
- `vendor/overtrue/socialite/tests/` -- OAuth provider tests
- `vendor/easywechat-composer/easywechat-composer/tests/` -- Composer plugin tests
- `vendor/pimple/pimple/.github/workflows/tests.yml` -- CI config
- `vendor/phpoffice/phpspreadsheet/` -- No test files included in dist

## Test File Organization

**Current State:** No test files exist for application code.

**Recommended Structure (if tests were to be added):**
```
tests/
├── bootstrap.php
├── admin/
│   ├── controller/
│   │   └── UserTest.php
│   ├── library/
│   │   └── AuthTest.php
│   └── validate/
│       └── UserTest.php
├── common/
│   ├── controller/
│   ├── library/
│   │   ├── AuthTest.php
│   │   └── UploadTest.php
│   └── model/
│       └── UserTest.php
├── api/
│   └── controller/
│       └── UserTest.php
├── extend/
│   └── fast/
│       └── RandomTest.php
├── fixtures/
│   └── database/
└── TestCase.php
```

## Mocking

**No mocking framework in use.**

**Dependencies that would need mocking for testing:**
- `think\Db` -- Database operations (query, startTrans, commit, rollback, name, table)
- `think\Config` -- Configuration access (`Config::get()`, `Config::set()`)
- `think\Request` -- HTTP request (`$this->request->post()`, `$this->request->isAjax()`)
- `think\Session` -- Session management
- `think\Cookie` -- Cookie operations
- `think\Hook` -- Event/hook system
- `think\Lang` -- Language/translation
- `think\Loader` -- Class autoloading
- `think\View` -- Template rendering
- `fast\Tree` -- Tree data structure
- `\app\common\library\Auth` -- Authentication singleton
- `\app\admin\library\Auth` -- Admin authentication singleton
- `GuzzleHttp\Client` -- HTTP client (used in `application/index/controller/Index.php`)

**Mocking Challenge:** The codebase relies heavily on ThinkPHP's singleton pattern (`Auth::instance()`) and static methods (`Db::name()`, `Config::get()`), making unit testing difficult without significant refactoring or a dedicated mocking framework like Mockery.

## Fixtures and Factories

**Current State:** No test fixtures or factories exist.

**Database fixtures would be needed for:**
- User records (admin users, regular users)
- Auth groups and rules
- Categories and attachments
- Config entries

## Coverage

**Current Coverage: 0%** -- No test coverage for any application code.

**Untested Modules (by priority):**

**High Priority (core business logic):**
| Module | File | Functionality |
|--------|------|---------------|
| Common Auth | `application/common/library/Auth.php` | User registration, login, token management, password encryption, email/mobile verification |
| Admin Auth | `application/admin/library/Auth.php` | Admin authentication, permission checking, breadcrumb generation |
| Backend Trait | `application/admin/library/traits/Backend.php` | CRUD operations: index, add, edit, del, multi, import, recyclebin, destroy, restore |
| Backend Controller | `application/common/controller/Backend.php` | `buildparams()` query building, `selectpage()` dropdown, data limit enforcement |
| Upload | `application/common/library/Upload.php` | File upload, validation, chunked upload, image processing |
| Token | `application/common/library/Token.php` | Token CRUD (MySQL/Redis drivers) |
| Security | `application/common/library/Security.php` | XSS cleaning, input sanitization |

**Medium Priority (data operations):**
| Module | File | Functionality |
|--------|------|---------------|
| User Model (common) | `application/common/model/User.php` | Money/score change logging, level calculation, avatar generation |
| User Model (admin) | `application/admin/model/User.php` | Password hashing on change, money/score audit logging |
| MoneyLog | `application/common/model/MoneyLog.php` | Financial transaction logging |
| ScoreLog | `application/common/model/ScoreLog.php` | Score transaction logging |
| User Controller | `application/admin/controller/user/User.php` | User management with avatar processing |
| Command Controller | `application/admin/controller/Command.php` | Online command generation and execution |
| Validators | `application/admin/validate/*.php` | Data validation rules for all entities |

**Low Priority (utilities):**
| Module | File |
|--------|------|
| Global Helpers | `application/common.php` (20+ functions) |
| Admin Helpers | `application/admin/common.php` |
| Random | `extend/fast/Random.php` |
| Date | `extend/fast/Date.php` |
| Tree | `extend/fast/Tree.php` |
| Rsa | `extend/fast/Rsa.php` |
| Form | `extend/fast/Form.php` |
| Http | `extend/fast/Http.php` |

## Code Quality Tools

**Static Analysis:**
- No PHPStan, Psalm, or PHPMD configured at project level
- PhpStorm `.idea/` directory contains transferred (inactive) configurations for PHPCS, PHPStan, and MessDetector
- No `.php-cs-fixer.php`, `phpcs.xml`, `phpmd.xml`, or `phpstan.neon` files

**Linting:**
- No ESLint, Prettier, or stylelint for frontend code
- `package.json` exists with Grunt build tasks only (minification, no linting)

**CI/CD:**
- No `.github/` directory (no GitHub Actions)
- No `.gitlab-ci.yml`
- No `Jenkinsfile`
- No `.travis.yml`
- No CI pipeline of any kind

**Build Tools:**
- Grunt for CSS/JS minification (`public/assets/js/*.min.js`, `public/assets/css/*.min.css`)
- `application/admin/command/Min.php` for asset minification
- `application/admin/command/Crud.php` for code generation
- `application/admin/command/Api.php` for API documentation generation
- `application/admin/command/Menu.php` for menu generation
- `application/admin/command/Install.php` for installation

**Composer Scripts:** None defined in `composer.json`

## Test Types

**Unit Tests:** Not used. No unit test files exist for any application code.

**Integration Tests:** Not used. No integration tests exist.

**E2E Tests:** Not used. No end-to-end testing framework (Selenium, Cypress, etc.) configured.

**Feature Tests:** Not used.

## Why No Tests

1. **FastAdmin Nature** -- This is a rapid development admin scaffold. FastAdmin projects prioritize speed over test coverage by design.
2. **No `require-dev`** -- `composer.json` has no testing-related dev dependencies (no PHPUnit, Mockery, etc.)
3. **No `scripts.test`** -- `composer.json` defines no test scripts
4. **No CI/CD** -- No continuous integration pipeline to enforce test execution
5. **Tight Coupling** -- Heavy reliance on ThinkPHP singletons and static methods makes unit testing difficult without significant refactoring
6. **Framework Philosophy** -- ThinkPHP 5.x ecosystem does not emphasize testing as a first-class concern

## Adding Tests: Recommended Setup

**Step 1: Add dev dependencies to `composer.json`:**
```json
"require-dev": {
    "phpunit/phpunit": "^9.6",
    "mockery/mockery": "^1.6"
}
```

**Step 2: Create `phpunit.xml` at project root:**
```xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php"
         colors="true"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Application Test Suite">
            <directory>./tests/</directory>
        </testsuite>
    </testsuites>
    <php>
        <env name="APP_ENV" value="testing"/>
    </php>
</phpunit>
```

**Step 3: Create `tests/bootstrap.php`:**
```php
<?php
// Load ThinkPHP bootstrap
define('APP_PATH', __DIR__ . '/../application/');
define('ROOT_PATH', __DIR__ . '/../');
define('RUNTIME_PATH', ROOT_PATH . 'runtime/');
require __DIR__ . '/../thinkphp/base.php';

// Set testing config
\think\Config::set('app_debug', false);
```

**Step 4: Add composer script:**
```json
"scripts": {
    "test": "phpunit"
}
```

**Run Commands (after setup):**
```bash
composer install --dev           # Install dev dependencies
vendor/bin/phpunit               # Run all tests
vendor/bin/phpunit --coverage-html coverage/  # Generate coverage report
composer test                    # Run via composer script
```

## Testing Challenges Specific to This Codebase

1. **Singleton Auth** -- `Auth::instance()` is called directly throughout, requiring careful mock setup or refactoring to dependency injection
2. **Static Db Calls** -- `Db::name()`, `Db::query()`, `Db::startTrans()` used everywhere instead of injected connections
3. **Global Functions** -- `__()`, `cdnurl()`, etc. depend on ThinkPHP runtime being bootstrapped
4. **Request Context** -- Controllers depend on `$this->request` populated by framework routing
5. **Session/Cookie** -- Many operations depend on session/cookie state
6. **Config Dependency** -- Heavy use of `Config::get()` makes isolation testing difficult
7. **View Rendering** -- Some tests would need to verify HTML output from templates

---

*Testing analysis: 2026-04-21*
