7425b263d5
- Add 4 CakePHP Claude Code skills: cakephp-unit-test, cakephp-test-setup, cakephp-test-review, cakephp-mock-helper - Add 11 CakePHP PHPUnit component templates (Table, Entity, Controller, Service, Command, Component, Middleware, Mailer, Form, Behavior, Helper) - Add CakePHP configs (phpunit.xml.dist, app_local.test.php for SQLite in-memory) - Add comprehensive CakePHP documentation and component guides - Update test-runner.sh and installer to auto-detect Laravel and CakePHP - Add CakePHP CI/CD templates for GitHub Actions and GitLab CI - Update system prompt, verification checklist, and README with dedicated guides
6.2 KiB
6.2 KiB
🧩 CakePHP Components Unit Testing Reference
Hướng dẫn chi tiết cách viết test cho từng tầng thành phần trong CakePHP (Table, Entity, Controller, Service, Command, Component, Middleware, Mailer, Form, Behavior).
1. Table Classes (src/Model/Table/*Table.php)
- Base Class:
Cake\TestSuite\TestCase - Các điểm cần test:
validationDefault(): Đầu vào hợp lệ, thiếu trường bắt buộc, sai format (email, regex, số âm).buildRules(): Quy tắc toàn vẹn dữ liệu (isUnique,existsIn).- Custom Finders (
findPublished(),findAuth()): Truy vấn trả về đúng bản ghi mong muốn. - Custom methods: Xử lý nghiệp vụ lưu dữ liệu.
namespace App\Test\TestCase\Model\Table;
use App\Model\Table\ArticlesTable;
use Cake\TestSuite\TestCase;
class ArticlesTableTest extends TestCase
{
protected ArticlesTable $Articles;
protected array $fixtures = ['app.Articles'];
protected function setUp(): void
{
parent::setUp();
$this->Articles = $this->getTableLocator()->get('Articles');
}
public function testFindPublished(): void
{
$query = $this->Articles->find('published');
$this->assertInstanceOf(\Cake\ORM\Query::class, $query);
$result = $query->toArray();
$this->assertNotEmpty($result);
foreach ($result as $article) {
$this->assertTrue($article->published);
}
}
}
2. Entity Classes (src/Model/Entity/*.php)
- Base Class:
Cake\TestSuite\TestCase - Các điểm cần test:
_setPassword()(Hashing logic).- Virtual Fields (
_getFullName()). $_accessibleproperties (Bảo vệ Mass Assignment).
namespace App\Test\TestCase\Model\Entity;
use App\Model\Entity\User;
use Cake\TestSuite\TestCase;
class UserTest extends TestCase
{
public function testPasswordIsHashed(): void
{
$user = new User(['password' => 'secret123']);
$this->assertNotEquals('secret123', $user->password);
$this->assertTrue((new \Authentication\PasswordHasher\DefaultPasswordHasher())->check('secret123', $user->password));
}
public function testVirtualFieldFullName(): void
{
$user = new User(['first_name' => 'John', 'last_name' => 'Doe']);
$this->assertSame('John Doe', $user->full_name);
}
}
3. Controller Classes (src/Controller/*Controller.php)
- Base Class:
Cake\TestSuite\TestCasevớiCake\TestSuite\IntegrationTestTrait - Các điểm cần test:
- HTTP Status:
200OK,302Redirect,403Forbidden,404Not Found,422Unprocessable Entity. - Flash messages:
$this->assertFlashMessage(). - Session & Auth: Giả lập đăng nhập qua
$this->session(). - CSRF & Security Tokens: Bắt buộc dùng
$this->enableCsrfToken()và$this->enableSecurityToken()khi test POST/PUT/DELETE.
- HTTP Status:
namespace App\Test\TestCase\Controller;
use Cake\TestSuite\IntegrationTestTrait;
use Cake\TestSuite\TestCase;
class ArticlesControllerTest extends TestCase
{
use IntegrationTestTrait;
protected array $fixtures = ['app.Articles', 'app.Users'];
public function testAddWithoutAuthRedirectsToLogin(): void
{
$this->get('/articles/add');
$this->assertRedirectContains('/login');
}
public function testAddSuccess(): void
{
$this->session(['Auth.User.id' => 1]);
$this->enableCsrfToken();
$this->enableSecurityToken();
$this->post('/articles/add', [
'title' => 'Sample Article',
'body' => 'Body text',
'published' => true,
]);
$this->assertRedirect(['action' => 'index']);
$this->assertFlashMessage('The article has been saved.');
}
}
4. Service Classes (src/Service/*.php)
- Base Class:
Cake\TestSuite\TestCase - Các điểm cần test:
- Các dependency được mock bằng PHPUnit Mock hoặc Mockery.
- Kiểm thử toàn bộ các nhánh rẽ điều kiện (Success, Invalid Data, 3rd-Party Failure).
namespace App\Test\TestCase\Service;
use App\Service\PaymentProcessingService;
use Cake\TestSuite\TestCase;
class PaymentProcessingServiceTest extends TestCase
{
public function testChargeSuccess(): void
{
$clientMock = $this->createMock(\App\External\StripeClient::class);
$clientMock->expects($this->once())
->method('createCharge')
->willReturn(['id' => 'ch_123', 'status' => 'succeeded']);
$service = new PaymentProcessingService($clientMock);
$result = $service->processOrder(100.0, 'tok_visa');
$this->assertTrue($result->isSuccess());
}
}
5. Console Command Classes (src/Command/*Command.php)
- Base Class:
Cake\TestSuite\TestCasevớiCake\Console\TestSuite\ConsoleIntegrationTestTrait - Các điểm cần test:
assertExitSuccess()vàassertExitError().assertOutputContains().- Arguments và Options flags.
namespace App\Test\TestCase\Command;
use Cake\Console\TestSuite\ConsoleIntegrationTestTrait;
use Cake\TestSuite\TestCase;
class SyncInventoryCommandTest extends TestCase
{
use ConsoleIntegrationTestTrait;
protected function setUp(): void
{
parent::setUp();
$this->useCommandRunner();
}
public function testSyncAll(): void
{
$this->exec('sync_inventory --all');
$this->assertExitSuccess();
$this->assertOutputContains('Inventory sync completed.');
}
}
6. Controller Component Classes (src/Controller/Component/*.php)
- Test logic tái sử dụng gắn vào Controller, dùng
ComponentRegistry.
7. Middleware Classes (src/Middleware/*.php)
- Test PSR-15 Middleware với
Cake\Http\ServerRequestvà Response Handler.
8. Mailer Classes (src/Mailer/*Mailer.php)
- Sử dụng
Cake\TestSuite\EmailTrait, kiểm tra email recipient, subject, và template body.
9. Form Classes (src/Form/*Form.php)
- Test standalone forms không gắn với ORM table (ContactForm, SearchFilterForm).
- Kiểm tra
validationDefault()và_execute().
10. Behavior Classes (src/Model/Behavior/*.php)
- Test ORM Behavior hooks (
beforeSave,beforeFind,afterSave).