assertions core coverage guides phpunit testing 測試指南 測試環境設定 composer require --dev nextpdf/core phpunit/phpunit
<!-- phpunit.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation= "vendor/phpunit/phpunit/phpunit.xsd"
bootstrap= "vendor/autoload.php"
beStrictAboutCoverageMetadata= "true"
failOnRisky= "true" >
<testsuites>
<testsuite name= "Unit" >
<directory> tests/Unit</directory>
</testsuite>
<testsuite name= "Integration" >
<directory> tests/Integration</directory>
</testsuite>
</testsuites>
<coverage>
<report>
<clover outputFile= "coverage.xml" />
</report>
</coverage>
</phpunit>
PDF 結構斷言 use NextPDF\Core\Testing\PdfAssertions;
use NextPDF\Core\Testing\PdfInspector;
use PHPUnit\Framework\TestCase;
final class InvoicePdfTest extends TestCase
{
use PdfAssertions;
private PdfInspector $inspector;
protected function setUp(): void
{
$document = $this->buildInvoiceDocument();
$this->inspector = PdfInspector::fromDocument($document);
}
public function test_pdf_has_correct_page_count(): void
{
$this->assertPdfPageCount($this->inspector, expected: 2);
}
public function test_pdf_contains_invoice_number(): void
{
$this->assertPdfContainsText($this->inspector, text: 'INV-2024-001');
}
public function test_pdf_is_a4_size(): void
{
$this->assertPdfPageSize($this->inspector, page: 1, size: PageSize::A4);
}
}
文字內容驗證 public function test_invoice_total_is_correct(): void
{
// 驗證特定頁面的文字內容
$text = $this->inspector->extractText(page: 1);
$this->assertStringContainsString('NT$ 12,650', $text);
$this->assertStringContainsString('稅前合計', $text);
}
public function test_text_at_position(): void
{
// 驗證特定位置的文字(適用精確版面測試)
$this->assertPdfTextAtPosition(
inspector: $this->inspector,
text: '客戶名稱',
x: 25.0,
y: 80.0,
tolerance: 1.0, // mm 容許誤差
);
}
頁面結構驗證 public function test_document_has_bookmarks(): void
{
$bookmarks = $this->inspector->bookmarks();
$this->assertCount(3, $bookmarks);
$this->assertEquals('第一章', $bookmarks[0]->title());
}
public function test_pdf_contains_embedded_image(): void
{
$images = $this->inspector->images(page: 1);
$this->assertCount(1, $images);
$this->assertGreaterThan(0, $images[0]->widthPx());
}
表單欄位驗證 public function test_form_has_required_fields(): void
{
$fields = $this->inspector->formFields();
$this->assertPdfHasFormField($this->inspector, name: 'customer_name');
$this->assertPdfFormFieldRequired($this->inspector, name: 'customer_name');
$this->assertPdfFormFieldType($this->inspector, name: 'customer_name', type: 'text');
}
安全性驗證 public function test_pdf_is_encrypted(): void
{
$this->assertPdfIsEncrypted($this->inspector);
$this->assertPdfEncryptionAlgorithm($this->inspector, algorithm: 'AES-256');
}
public function test_pdf_has_valid_signature(): void
{
$signatures = $this->inspector->signatures();
$this->assertCount(1, $signatures);
$this->assertTrue($signatures[0]->isValid());
$this->assertEquals('PAdES-B-B', $signatures[0]->level());
}
無障礙合規測試 public function test_pdf_is_tagged(): void
{
$this->assertPdfIsTagged($this->inspector);
$this->assertPdfLanguage($this->inspector, language: 'zh-TW');
}
public function test_all_images_have_alt_text(): void
{
$this->assertPdfImagesHaveAltText($this->inspector);
}
測試固定裝置(Fixtures) // tests/Fixtures/DocumentFixture.php
final class DocumentFixture
{
public static function minimalA4(): Document
{
return Document::createStandalone(pageSize: PageSize::A4);
}
public static function withChineseText(): Document
{
$doc = self::minimalA4();
$doc->text()->write(
text: '測試文字',
position: Position::at(x: 25.0, y: 50.0),
fontName: 'NotoSansCJKtc',
);
return $doc;
}
}
快照測試 public function test_invoice_matches_snapshot(): void
{
$document = $this->buildInvoiceDocument();
$this->assertMatchesPdfSnapshot(
document: $document,
snapshotPath: __DIR__ . '/snapshots/invoice-v2.pdf',
tolerance: 0.01, // 允許 1% 的差異(字型渲染差異)
);
}
覆蓋率要求 # 執行測試並生成覆蓋率報告
php -d pcov.enabled= 1 vendor/bin/phpunit \
--coverage-clover coverage.xml \
--testsuite Unit,Integration
# 在本地驗覆蓋率
vendor/bin/phpunit --coverage-text
延伸閱讀