跳轉到

測試指南

測試環境設定

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

延伸閱讀