Aktuel situation: PHP2Shell. To kritiske PHP-sårbarheder (CVSS 9,2) tillader skadelig kode uden login. Rettelser siden 21.10.2026.Hvad der skal gøres nu →

Test PHP-kode: PHPUnit og Pest

PHPUnit er standardværktøjet til PHP-tests, Pest bygger oven på det. Den, der har tests, kan indspille sikkerhedsopdateringer og versionsskift hurtigere og med mindre risiko.

Status 4 min. læsetidPHP-viden

Kort sagt: PHPUnit er standardværktøjet til automatisk at teste PHP-kode; Pest er et framework med en kortere skrivemåde, som bygger på det. Aktuelt er PHPUnit 13 (siden februar 2026, fra PHP 8.4), Pest foreligger i version 5. Automatiske tests lukker ingen sårbarheder i selve PHP, men de gør opdateringer planlægbare: Efter PHP2Shell og før udløbet af understøttelsen af PHP 8.2 den 31.12.2026 er det den afgørende fordel.

Hvorfor teste PHP-kode?

For ledelsen kan nytten sammenfattes i én sætning: Tests gør ændringer billigere og sikrere. En automatisk test kontrollerer på sekunder, om en funktion stadig gør, hvad den skal, f.eks. om en indkøbskurv regner rigtigt, eller et login afviser forkerte adgangskoder. Uden tests kontrollerer et menneske det i hånden, eller ingen gør.

Forskellen bliver især tydelig ved opdateringer. Skal PHP opdateres med kort varsel på grund af en kritisk sårbarhed, tøver mange driftsansvarlige, fordi de frygter fejl i shoppen eller kundeportalen. Med en testsuite kører opdateringen først i et testmiljø, testene viser problemer, og derefter går det live.

PHPUnit: standarden for PHP-tests

PHPUnit udkommer hvert år i februar i en ny hovedversion. Hver version forudsætter en mindsteversion af PHP og får omkring to års fejlrettelser. Ifølge phpunit.de gælder:

PHPUnit Udgivet PHP-forudsætning Fejlrettelser til
13 06.02.2026 fra PHP 8.4 04.02.2028
12 07.02.2025 fra PHP 8.3 05.02.2027
11 02.02.2024 fra PHP 8.2 06.02.2026
10 03.02.2023 fra PHP 8.1 07.02.2025

Tabellen viser en praktisk sammenhæng: Et projekt, der stadig bruger PHPUnit 10, kører oftest også stadig på en gammel PHP-version. Testværktøjer og PHP-version bør løftes sammen. PHPUnit installeres sædvanligvis via Composer som udviklingsafhængighed.

En første test med PHPUnit

En test er en klasse, der arver fra PHPUnit\Framework\TestCase. Testmetoder er offentlige og begynder med test, alternativt markerer man dem med attributten #[Test]. Eksemplet kontrollerer en enkel funktion til prisberegning:

<?php declare(strict_types=1);

use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;

final class BruttopreisTest extends TestCase
{
    public static function preise(): array
    {
        return [
            'Normalsatz'   => [10000, 19, 11900],
            'Ermäßigt'     => [10000, 7, 10700],
            'Null bleibt Null' => [0, 19, 0],
        ];
    }

    #[DataProvider('preise')]
    public function testBruttopreisInCent(int $netto, int $satz, int $erwartet): void
    {
        $this->assertSame($erwartet, bruttopreis($netto, $satz));
    }
}

Data provideren leverer flere tilfælde til den samme test. Ifølge PHPUnit-dokumentationen skal den være offentlig og statisk. Der regnes i cent som heltal, så der ikke opstår afrundingsfejl på grund af kommatal. Suiten udføres med ./vendor/bin/phpunit, hvis PHPUnit er installeret via Composer.

Pest: samme basis, kortere skrivemåde

Pest er ifølge dokumentationen bygget på PHPUnit. Tests skrives som funktioner med it() eller test() og forventninger med expect(). Pest 5 forudsætter PHP 8.4. Installationen ifølge dokumentationen:

composer remove phpunit/phpunit
composer require pestphp/pest --dev --with-all-dependencies
./vendor/bin/pest --init

Den samme test i Pest-skrivemåde:

<?php
it('berechnet den Bruttopreis zum Normalsatz', function () {
    expect(bruttopreis(10000, 19))->toBe(11900);
});

Eksisterende PHPUnit-tests omdanner pluginet pestphp/pest-plugin-drift for størstedelens vedkommende automatisk. Hvilken skrivemåde et team vælger, er en smagssag; afgørende er, at tests kører regelmæssigt.

Hvilke testtyper der er fornuftige

  1. Unit-tests: kontrollerer enkelte funktioner og klasser uden database eller netværk.
  2. Integrationstests: kontrollerer samspillet med database, filsystem eller grænseflader.
  3. Funktionstests via HTTP: kalder sider og formularer, som en browser gør.
  4. Sikkerheds-regressionstests: fastholder rettede fejl, f.eks. at output maskeres med htmlspecialchars(), eller at et login mislykkes efter en forkert adgangskode.
  5. Smoke-tests efter udrulningen: få hurtige kontroller af, om live-siden svarer efter en opdatering.

Som supplement til tests finder den statiske analyse med PHPStan og Psalm fejl uden at udføre koden.

Tests som sikkerhedsnet for opdateringer og PHP2Shell

PHP2Shell har vist, hvor kort tiden mellem offentliggørelse og handlepres kan være: Varsling den 20.10.2026, patches den 21.10.2026, BSI-advarselsniveau orange. Den, der havde en testsuite, kunne indspille PHP 8.4.27 eller 8.3.36 i et testmiljø, lade testene køre og gå live samme dag. Uden tests var valget ofte kun mellem en ukontrolleret opdatering og en åben sårbarhed.

Endnu større er nytten ved skift af hovedversion. For PHP 8.1 og ældre findes der ikke længere officielle opdateringer, og PHP 8.2 slutter den 31.12.2026, som siden PHP end of life forklarer. En testkørsel mod målversionen viser tidligt, hvilke forældede funktioner der skal erstattes. Fornuftigt er en CI-pipeline, der kører tests mod flere PHP-versioner, dertil et blik på release candidates som PHP 8.6.0, dog aldrig i produktion.

Tip

Skriv en test til hver rettet sikkerhedsfejl i jeres applikation. Så sikrer I, at den samme fejl ikke vender tilbage ved en senere ændring.

Hvordan hjælper PHP SOS konkret?

Ved migreringen fra PHP 8.1 og ældre og ved løbende opdateringer støtter vi sådan:

  • Vurdere beholdningen: Hvilke tests findes der, hvilke PHP- og PHPUnit-versioner kører, og hvor mangler der tests til kritiske forløb?
  • Skabe en mindstedækning: Sammen med jeres udviklingsteam eller bureau sikrer vi login, formularer og bestillingsforløb med tests.
  • Teste opdateringer: Nye PHP-versioner kører først i et testmiljø mod suiten.
  • Dokumentere resultatet: I får testresultater og versionsstatus som dokumentation for patch- eller migreringstrinnet.

Ofte stillede spørgsmål

Hvilken PHPUnit-version har jeg brug for?

Det afhænger af jeres PHP-version. PHPUnit 13 forudsætter PHP 8.4, PHPUnit 12 PHP 8.3 og PHPUnit 11 PHP 8.2. Den aktuelle tabel står på phpunit.de under de understøttede versioner.

Er Pest en erstatning for PHPUnit?

Pest er ifølge sin egen dokumentation bygget på PHPUnit og tilbyder en kortere skrivemåde. Eksisterende PHPUnit-tests kan for størstedelens vedkommende omdannes automatisk med Drift-pluginet, nogle skal tilpasses i hånden.

Hjælper tests mod sårbarheder i selve PHP?

Ikke direkte. Sårbarheder som PHP2Shell sidder i fortolkeren og lukkes ved en PHP-opdatering. Tests sørger dog for, at I hurtigt kan indspille denne opdatering uden frygt for ubemærkede fejl i applikationen.

Hvor mange tests er nok?

Der findes intet fast tal. Fornuftigt er først at dække de forretningskritiske veje: login, bestilling, formularer, grænseflader. Derefter vokser testdækningen med hver ændring og hver rettet fejl.

Kilder

Akut kontakt

Hver time tæller. Skriv til os nu.

Beskriv kort system, PHP-version og observation. Vi vender tilbage, afklarer situationen og arbejder på afstand, indtil hændelsen er afsluttet og dokumenteret.

Akut hjælp