laravel-quality
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLaravel Quality
Laravel 代码质量保障
Testing, static analysis, and code quality enforcement.
Related guides:
- code-style.md - Laravel Pint configuration and coding style
- type-safety.md - Strict types and type hints
- Testing - Comprehensive testing guide
测试、静态分析与代码质量管控。
相关指南:
- code-style.md - Laravel Pint 配置与编码风格
- type-safety.md - 严格类型与类型提示
- Testing - 全面测试指南
Quality Stack
质量工具栈
bash
undefinedbash
undefinedcomposer.json scripts
composer.json 脚本
{
"test": "pest",
"analyse": "phpstan analyse",
"format": "pint",
"quality": [
"@analyse",
"@test"
]
}
All files must have `declare(strict_types=1)` at top. Run quality checks before every commit.{
"test": "pest",
"analyse": "phpstan analyse",
"format": "pint",
"quality": [
"@analyse",
"@test"
]
}
所有文件顶部必须声明 `declare(strict_types=1)`。每次提交前需运行质量检查。Architecture Tests (Pest)
架构测试(Pest)
Setup
设置
tests/Pest.phpphp
pest()->extend(Tests\TestCase::class)->in('Feature', 'Unit');tests/Pest.phpphp
pest()->extend(Tests\TestCase::class)->in('Feature', 'Unit');Core Architecture Tests
核心架构测试
tests/Architecture/ActionsTest.phpphp
<?php
declare(strict_types=1);
arch('actions are invokable')
->expect('App\Actions')
->toHaveMethod('__invoke');
arch('actions live in Actions namespace')
->expect('App\Actions')
->toBeClasses()
->toOnlyBeUsedIn('App\Actions', 'App\Http', 'App\Jobs', 'App\Listeners');
arch('actions do not use models directly')
->expect('App\Actions')
->not->toUse('Illuminate\Database\Eloquent\Model');tests/Architecture/DataTest.phpphp
<?php
declare(strict_types=1);
arch('data objects extend base Data class')
->expect('App\Data')
->toExtend('App\Data\Data')
->ignoring('App\Data\Data');
arch('data objects use constructor property promotion')
->expect('App\Data')
->toHaveConstructor();tests/Architecture/StrictTypesTest.phpphp
<?php
declare(strict_types=1);
arch('app files declare strict types')
->expect('App')
->toUseStrictTypes();
arch('test files declare strict types')
->expect('Tests')
->toUseStrictTypes();tests/Architecture/ControllersTest.phpphp
<?php
declare(strict_types=1);
arch('controllers do not use DB facade')
->expect('App\Http')
->not->toUse('Illuminate\Support\Facades\DB');
arch('controllers do not use models directly')
->expect('App\Http\Web\Controllers')
->not->toUse('App\Models');tests/Architecture/NamingTest.phpphp
<?php
declare(strict_types=1);
arch('actions end with Action suffix')
->expect('App\Actions')
->toHaveSuffix('Action');
arch('data objects end with Data suffix')
->expect('App\Data')
->toHaveSuffix('Data')
->ignoring('App\Data\Data', 'App\Data\Concerns');
arch('exceptions end with Exception suffix')
->expect('App\Exceptions')
->toHaveSuffix('Exception')
->ignoring('App\Exceptions\Concerns');tests/Architecture/ModelsTest.phpphp
<?php
declare(strict_types=1);
arch('models use custom query builders')
->expect('App\Models')
->toHaveMethod('newEloquentBuilder');
arch('models do not use local scopes')
->expect('App\Models')
->not->toHaveMethod('scope*');tests/Architecture/ActionsTest.phpphp
<?php
declare(strict_types=1);
arch('actions are invokable')
->expect('App\Actions')
->toHaveMethod('__invoke');
arch('actions live in Actions namespace')
->expect('App\Actions')
->toBeClasses()
->toOnlyBeUsedIn('App\Actions', 'App\Http', 'App\Jobs', 'App\Listeners');
arch('actions do not use models directly')
->expect('App\Actions')
->not->toUse('Illuminate\Database\Eloquent\Model');tests/Architecture/DataTest.phpphp
<?php
declare(strict_types=1);
arch('data objects extend base Data class')
->expect('App\Data')
->toExtend('App\Data\Data')
->ignoring('App\Data\Data');
arch('data objects use constructor property promotion')
->expect('App\Data')
->toHaveConstructor();tests/Architecture/StrictTypesTest.phpphp
<?php
declare(strict_types=1);
arch('app files declare strict types')
->expect('App')
->toUseStrictTypes();
arch('test files declare strict types')
->expect('Tests')
->toUseStrictTypes();tests/Architecture/ControllersTest.phpphp
<?php
declare(strict_types=1);
arch('controllers do not use DB facade')
->expect('App\Http')
->not->toUse('Illuminate\Support\Facades\DB');
arch('controllers do not use models directly')
->expect('App\Http\Web\Controllers')
->not->toUse('App\Models');tests/Architecture/NamingTest.phpphp
<?php
declare(strict_types=1);
arch('actions end with Action suffix')
->expect('App\Actions')
->toHaveSuffix('Action');
arch('data objects end with Data suffix')
->expect('App\Data')
->toHaveSuffix('Data')
->ignoring('App\Data\Data', 'App\Data\Concerns');
arch('exceptions end with Exception suffix')
->expect('App\Exceptions')
->toHaveSuffix('Exception')
->ignoring('App\Exceptions\Concerns');tests/Architecture/ModelsTest.phpphp
<?php
declare(strict_types=1);
arch('models use custom query builders')
->expect('App\Models')
->toHaveMethod('newEloquentBuilder');
arch('models do not use local scopes')
->expect('App\Models')
->not->toHaveMethod('scope*');Static Analysis (PHPStan)
静态分析(PHPStan)
Installation
安装
bash
composer require phpstan/phpstan --dev
composer require phpstan/phpstan-strict-rules --dev
composer require larastan/larastan --devbash
composer require phpstan/phpstan --dev
composer require phpstan/phpstan-strict-rules --dev
composer require larastan/larastan --devConfiguration
配置
phpstan.neonneon
includes:
- vendor/larastan/larastan/extension.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
parameters:
level: 8
paths:
- app
- tests
excludePaths:
- app/Providers/TelescopeServiceProvider.php
checkMissingIterableValueType: true
checkGenericClassInNonGenericObjectType: true
reportUnmatchedIgnoredErrors: falsephpstan.neonneon
includes:
- vendor/larastan/larastan/extension.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
parameters:
level: 8
paths:
- app
- tests
excludePaths:
- app/Providers/TelescopeServiceProvider.php
checkMissingIterableValueType: true
checkGenericClassInNonGenericObjectType: true
reportUnmatchedIgnoredErrors: falseRun
运行
bash
./vendor/bin/phpstan analysebash
./vendor/bin/phpstan analyseCode Style (Laravel Pint)
代码风格(Laravel Pint)
Installation
安装
bash
composer require laravel/pint --devbash
composer require laravel/pint --devConfiguration
配置
pint.jsonjson
{
"preset": "laravel",
"rules": {
"simplified_null_return": true,
"no_unused_imports": true,
"ordered_imports": {
"sort_algorithm": "alpha"
}
}
}pint.jsonjson
{
"preset": "laravel",
"rules": {
"simplified_null_return": true,
"no_unused_imports": true,
"ordered_imports": {
"sort_algorithm": "alpha"
}
}
}Run
运行
bash
./vendor/bin/pint
./vendor/bin/pint --test # Check onlybash
./vendor/bin/pint
./vendor/bin/pint --test # 仅检查不修复Test Coverage
测试覆盖率
Enable Coverage (Pest)
启用覆盖率(Pest)
phpunit.xmlxml
<coverage>
<report>
<html outputDirectory="coverage"/>
<text outputFile="php://stdout"/>
</report>
</coverage>phpunit.xmlxml
<coverage>
<report>
<html outputDirectory="coverage"/>
<text outputFile="php://stdout"/>
</report>
</coverage>Run with Coverage
带覆盖率运行测试
bash
./vendor/bin/pest --coverage
./vendor/bin/pest --coverage --min=80 # Enforce minimumbash
./vendor/bin/pest --coverage
./vendor/bin/pest --coverage --min=80 # 强制最低覆盖率要求CI/CD Checks
CI/CD 检查
GitHub Actions Example
GitHub Actions 示例
.github/workflows/tests.ymlyaml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.4
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite
coverage: xdebug
- name: Install Dependencies
run: composer install --prefer-dist --no-interaction
- name: Code Style
run: ./vendor/bin/pint --test
- name: Static Analysis
run: ./vendor/bin/phpstan analyse
- name: Run Tests
run: ./vendor/bin/pest --coverage --min=80.github/workflows/tests.ymlyaml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.4
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite
coverage: xdebug
- name: Install Dependencies
run: composer install --prefer-dist --no-interaction
- name: Code Style
run: ./vendor/bin/pint --test
- name: Static Analysis
run: ./vendor/bin/phpstan analyse
- name: Run Tests
run: ./vendor/bin/pest --coverage --min=80Pre-commit Hooks
提交前钩子
Installation
安装
bash
composer require brainmaestro/composer-git-hooks --devbash
composer require brainmaestro/composer-git-hooks --devConfiguration
配置
composer.jsonjson
{
"extra": {
"hooks": {
"pre-commit": [
"./vendor/bin/pint",
"./vendor/bin/phpstan analyse",
"./vendor/bin/pest"
]
}
},
"scripts": {
"post-install-cmd": "vendor/bin/cghooks add --ignore-lock",
"post-update-cmd": "vendor/bin/cghooks update"
}
}composer.jsonjson
{
"extra": {
"hooks": {
"pre-commit": [
"./vendor/bin/pint",
"./vendor/bin/phpstan analyse",
"./vendor/bin/pest"
]
}
},
"scripts": {
"post-install-cmd": "vendor/bin/cghooks add --ignore-lock",
"post-update-cmd": "vendor/bin/cghooks update"
}
}Quality Metrics
质量指标
What to Track
需追踪的指标
- Test coverage - Aim for 80%+
- PHPStan level - Level 8 (max)
- Architecture test pass rate - 100%
- Code style violations - 0
- 测试覆盖率 - 目标80%+
- PHPStan 级别 - 级别8(最高)
- 架构测试通过率 - 100%
- 代码风格违规数 - 0
Regular Reviews
定期评审
- Weekly - Check test coverage trends
- Per PR - Run all quality checks
- Monthly - Review architecture compliance
- Release - Full quality audit
- 每周 - 检查测试覆盖率趋势
- 每个PR - 运行所有质量检查
- 每月 - 评审架构合规性
- 发布阶段 - 全面质量审计
Common Issues to Watch
需关注的常见问题
Anti-patterns
反模式
- Domain logic in controllers
- Using scopes instead of builders
- Missing strict types declaration
- Passing primitives instead of DTOs
- Jobs/Listeners with domain logic
- 控制器中包含领域逻辑
- 使用作用域而非查询构建器
- 缺失严格类型声明
- 传递原始类型而非DTO
- 任务/监听器中包含领域逻辑
Type Safety
类型安全
- Missing return types
- Missing parameter types
- Missing property types
- Untyped arrays/collections
- 缺失返回类型
- 缺失参数类型
- 缺失属性类型
- 未类型化的数组/集合
Testing
测试
- Missing feature tests for endpoints
- Missing unit tests for actions
- Low coverage on critical paths
- Brittle tests (too many mocks)
- 端点缺失功能测试
- 动作缺失单元测试
- 关键路径覆盖率低
- 脆弱测试(过多Mock)
Enforcement Strategy
执行策略
- Architecture tests - Automated checks
- PR reviews - Manual verification
- CI/CD gates - Block failing builds
- Team standards - Document + training
- Pair programming - Share knowledge
- 架构测试 - 自动化检查
- PR评审 - 人工验证
- CI/CD 门禁 - 阻止失败构建
- 团队标准 - 文档化+培训
- 结对编程 - 知识共享