285 lines
11 KiB
Markdown
285 lines
11 KiB
Markdown
# 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*
|