Integraatio- ja toiminnallinen testaus
Testatkaa, miten komponentit toimivat yhdessä käytännössä.
Integraatio- ja toiminnallinen testaus on ilmainen PHP Academy-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu PHP Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. PHP Academy-kurssilla on yhteensä 4 oppituntia.
Yksikkötestausta pidemmälle
Yksikkötestit osoittavat, että luokka toimii eristyksissä, kun kaikki riippuvuudet on korvattu mockeilla. Mockit voivat kuitenkin johtaa harhaan — oikea tietokanta, frameworkin reititin tai HTTP-kerros toimii eri tavalla. Integraatiotestit varmistavat, että vähintään kaksi oikeaa komponenttia toimii yhteen kytkettynä; toiminnalliset testit käyvät sovelluksen läpi päästä päähän sen julkisen sisääntulopisteen (HTTP-pyyntö tai konsolikomento) kautta. Tässä oppitunnissa käsitellään ja kirjoitetaan molempia.
Testipyramidi
Hyvä testikokoelma on pyramidin muotoinen:
- Paljon yksikkötestejä — nopeita, eristettyjä ja jatkuvasti ajettavia.
- Vähemmän integraatiotestejä — oikea tietokanta, jono ja välimuisti; hitaampia.
- Vähän toiminnallisia/E2E-testejä — koko pino, hitaimpia ja herkimpiä rikkoutumaan.
Tämän kääntäminen toisinpäin, jolloin syntyy pääasiassa E2E-testeistä koostuva jäätelötötterö, tuottaa hitaan ja epävakaan testikokoelman. Siirtäkää kattavuutta alemmille tasoille aina kun mahdollista.
Integraatio: repository oikeaa tietokantaa vasten
Repositoryn integraatiotesti käyttää oikeaa tietokantayhteyttä — ei mockia — ja paljastaa SQL-, skeema- ja yhdistämisvirheitä. Käyttäkää erillistä testitietokantaa (tai muistissa toimivaa SQLite-tietokantaa, joka vastaa käyttämäänne murretta riittävän hyvin) ja oikeaa PDO:ta.
<?php
use PHPUnit\Framework\TestCase;
final class UserRepositoryTest extends TestCase
{
private \PDO $pdo;
protected function setUp(): void
{
$this->pdo = new \PDO('sqlite::memory:');
$this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$this->pdo->exec('CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT)');
}
public function test_persists_and_finds_a_user(): void
{
$repo = new UserRepository($this->pdo);
$id = $repo->create('ada@example.com');
self::assertSame('ada@example.com', $repo->find($id)->email);
}
}
Eristys: transaktion palauttaminen
Integraatiotestit eivät saa vuotaa tilaa toisiinsa. Nopein tapa on kääriä jokainen testi transaktion sisään ja tehdä rollback tearDown()-metodissa — tietokanta palautuu puhtaaseen alkutilaan ilman uudelleentäyttöä. (Trunkkaus on varavaihtoehto, jos testattava koodi tekee commitin tai käyttää DDL:ää.)
<?php
protected function setUp(): void
{
$this->pdo = TestDb::connection();
$this->pdo->beginTransaction();
}
protected function tearDown(): void
{
$this->pdo->rollBack(); // undo everything this test did
}
Testidata ja factoryt
Testit tarvitsevat dataa. Välttäkää hauraita valtavia SQL-vedoksia ja suosikaa pieniä factoryja, jotka luovat vain testin tarvitsemat rivit ja tarjoavat järkevät oletusarvot, joita voi muuttaa tapauskohtaisesti. Näin jokaisen testin tarkoitus pysyy selvänä, ja testit kestävät skeeman kasvamisen.
<?php
final class UserFactory
{
public static function create(\PDO $pdo, array $overrides = []): int
{
$data = array_merge(['email' => 'user'.uniqid().'@test.dev'], $overrides);
$stmt = $pdo->prepare('INSERT INTO users (email) VALUES (:email)');
$stmt->execute($data);
return (int) $pdo->lastInsertId();
}
}
Toiminnallinen testaus: sovellusta ajetaan asiakkaan tavoin
Toiminnallinen testi käyttää oikeaa sovelluksen kerneliä ja reititintä simuloidulla pyynnöllä ja tarkistaa vastauksesta tilakoodin, otsakkeet ja rungon. Symfonyn WebTestCase ja Laravelin HTTP-testauksen apufunktiot tekevät juuri tämän käynnistämättä oikeaa web-palvelinta. Alla on Symfony-rakenne.
<?php
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
final class HealthControllerTest extends WebTestCase
{
public function test_health_endpoint_returns_ok(): void
{
$client = static::createClient();
$client->request('GET', '/health');
self::assertResponseIsSuccessful(); // 2xx
self::assertJson($client->getResponse()->getContent());
}
}
Vastauksen tarkistaminen
Toiminnallisissa testeissä tarkistetaan rajapinnan havaittava toiminta: tila, JSON-rakenne ja tietokantaan kohdistuvat sivuvaikutukset. Alla oleva POST luo resurssin; tarkistamme sekä HTTP-vastauksen että sen, että tietue todella tallentui tietokantaan — näin varmistamme koko pinon toimineen yhdessä.
<?php
public function test_creating_a_user_persists_it(): void
{
$client = static::createClient();
$client->request('POST', '/users', server: [
'CONTENT_TYPE' => 'application/json',
], content: json_encode(['email' => 'ada@example.com']));
self::assertResponseStatusCodeSame(201);
$repo = static::getContainer()->get(UserRepository::class);
self::assertNotNull($repo->findByEmail('ada@example.com'));
}
Ulkoisten rajojen valikoiva feikkaus
Toiminnallisten testienkaan ei pitäisi kutsua oikeita maksupalveluntarjoajia tai lähettää oikeita sähköposteja. Korvatkaa vain uloimmat ulkoiset palvelut — vaihtakaa ne testikontissa feikkeihin tai muistissa toimiviin toteutuksiin — ja pitäkää oma koodinne, reitityksenne ja tietokantanne oikeina. Näin päästä päähän -uskollisuus säilyy ilman epävakaita verkkokutsuja.
<?php
public function test_checkout_charges_via_gateway(): void
{
$client = static::createClient();
// Replace the real gateway binding with an in-memory fake:
static::getContainer()->set(PaymentGateway::class, new FakePaymentGateway());
$client->request('POST', '/checkout', content: json_encode(['cart' => 1]));
self::assertResponseIsSuccessful();
}
Erilliset testikokoelmat ja nopeudet
Jakakaa phpunit.xml testikokoelmiin, jotta nopea yksikkötestikokoelma voidaan ajaa jokaisen tallennuksen yhteydessä ja hitaat integraatio- ja toiminnalliset testikokoelmat tarvittaessa tai CI:ssä. Ryhmitelkää testit hakemistoittain ja valitkaa ne --testsuite-valitsimella.
<phpunit>
<testsuites>
<testsuite name="unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="integration">
<directory>tests/Integration</directory>
</testsuite>
<testsuite name="functional">
<directory>tests/Functional</directory>
</testsuite>
</testsuites>
</phpunit>Deterministisyys on kattavuutta tärkeämpää
Nopein tapa menettää luottamus testikokoelmaan on testien epävakaus. Tehkää integraatio- ja toiminnallisista testeistä deterministisiä:
- Jäädyttäkää aika injektoimalla kello sen sijaan, että kutsuisitte
time()-funktiota. - Asettakaa satunnaislukugeneraattorin siemen ja välttäkää järjestämättömien kyselyjen tulosten järjestyksestä riippuvia tarkistuksia.
- Palauttakaa tietokannan tila jokaisen testin jälkeen (transaktion rollback tai trunkkaus).
- Älkää koskaan riippuko testien suoritusjärjestyksestä.
Testitietokannan on vastattava tuotantoa
Muistissa toimiva SQLite on nopea, mutta murteiden väliset erot (kirjainkokoherkkyys, JSON-funktiot, viiteavainten valvonta ja tyypit) voivat peittää virheitä, jotka tulevat esiin vasta oikeassa moottorissa. Jos koodinne käyttää moottorikohtaista SQL:ää, ajakaa integraatiotestit samalla moottorilla kuin tuotannossa — CI:ssä tämä on usein kertakäyttöinen Docker-kontti — kätevän korvikkeen sijaan.
<?php
// Read connection from environment so CI points at a real Postgres/MySQL container
$dsn = getenv('TEST_DATABASE_URL') ?: 'sqlite::memory:';
$pdo = new \PDO($dsn);
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
// In CI, TEST_DATABASE_URL targets the same engine as production.
Pikatarkistus
Miten toiminnallisessa testissä pitäisi käsitellä kolmannen osapuolen maksupalveluntarjoajaa?
Kertaus
Opitte testaamaan komponentteja yhdessä:
- Integraatiotestit käyttävät oikeita tietokantoja ja palveluita paljastaakseen sen, minkä mockit peittävät; eristäkää ne transaktion rollbackilla.
- Toiminnalliset testit käyttävät oikeaa kerneliä simuloitujen pyyntöjen kautta ja tarkistavat vastaukset sekä sivuvaikutukset.
- Factoryt luovat mahdollisimman vähän testidataa; feikatkaa vain uloimmat ulkoiset rajapinnat.
- Jakakaa testikokoelmat nopeuden perusteella ja pitäkää hitaammat testit deterministisinä.
Seuraavaksi: testien laadun mittaaminen mutaatiotestauksella.
Opi PHP tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 49
- Oppitunnit
- 195
Usein kysytyt kysymykset
Onko oppitunti ”Integraatio- ja toiminnallinen testaus” ilmainen?
Kyllä – oppitunnin ”Integraatio- ja toiminnallinen testaus” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko PHP Academy-kurssin, päivitä CoddyKit PROhon. PHP Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Integraatio- ja toiminnallinen testaus”?
Testatkaa, miten komponentit toimivat yhdessä käytännössä. Harjoittelet PHP Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni PHP Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin PHP Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.
Kuinka kauan ”Integraatio- ja toiminnallinen testaus”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä PHP Academy-oppitunnilla?
Kyllä. Jokainen PHP Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Testiohjatun kehityksen työnkulku
- Mockaus ja stubit Mockerylla
- Integraatio- ja toiminnallinen testaus
- Mutaatiotestaus Infectionilla