CI CD folyamat beállítása tesztautomatizálással.

A CI folyamat varázsa: automatikus tesztelés és kódellenőrzés egyben

Sziasztok kollégák! Ma arról szeretnék mesélni, hogyan változtathatja meg a mindennapjaitokat egy jól megtervezett CI folyamat. Ha valaha is elgondolkoztatok azon, hogy „biztonságosan” deployolhatnátok anélkül, hogy félnétek attól, hogy minden összeomlik, vagy hogy a kódminőség egyre csúszik lefelé, akkor pontosan erről fogunk beszélni.

Mi is az a CI/CD valójában?

CI a Continuous Integration rövidítése, ami folyamatos integrációt jelent. A lényege, hogy minél gyakrabban integráljuk a kódunkat egy közös tárhelyre (általában git), és minden egyes alkalommal lefuttatunk egy sor automatizált ellenőrzést. A CD pedig vagy Continuous Delivery (folyamatos kézbesítés) vagy Continuous Deployment (folyamatos telepítés) – az első esetben készen áll a deploy-ra, a másodikban pedig automatikusan élesedik.

A legnagyobb tévhit, hogy ez csak nagy projekteknek vagy cégeknek fontos. Valójában akár egy személyes projektben is óriási időt takaríthat meg, és megvéd a kínos buktatóktól.

Miért éri meg beállítani?

Képzeljétek el a következőt: épp siettek, mert holnap délutánra kellene egy új funkció. Összedobtok valamit, átfuttattok pár tesztet manuálisan, és felteszitek a kódot. Másnap reggelre a főnökök panaszokat kapnak, hogy valami eltört a regisztrációban. Kiderül, hogy a pull requestetekben volt egy elírás egy jQuery eseménykezelőben, ami csak bizonyos böngészőkben jelentkezett.

Egy CI folyamat ezt elkapja már a fejlesztés korai szakaszában. Automatikusan futtatja a teszteket, ellenőrzi a kódstílust, és akár alapszintű biztonsági vizsgálatot is végez.

Egy tipikus CI folyamat felépítése

Nézzünk egy konkrét példát egy PHP backenddel és jQuery/Bootstrap frontenddel rendelkező projekthez. A folyamatunk három fő lépésből áll:

1. Kódminőség ellenőrzés (linting, coding standards) 2. Automatikus tesztelés (unit tesztek, integrációs tesztek) 3. Építés és csomagolás (dependencia install, asset-ek buildelése)

Íme egy egyszerűsített .gitlab-ci.yml fájl (hasonló a GitHub Actionshoz is), ami bemutatja a folyamatot:

stages:
  - lint
  - test
  - build

php-linting:
  stage: lint
  image: php:8.2
  script:
    - composer install
    - vendor/bin/phpcs --standard=PSR12 src/

javascript-quality:
  stage: lint
  image: node:18
  script:
    - npm install
    - npx eslint assets/js/
    - npx stylelint "assets/scss/**/*.scss"

php-tests:
  stage: test
  image: php:8.2
  services:
    - mysql:8.0
  variables:
    MYSQL_ROOT_PASSWORD: password
  script:
    - composer install
    - php vendor/bin/phpunit tests/ --coverage-text

frontend-tests:
  stage: test
  image: node:18
  script:
    - npm install
    - npm test

build-assets:
  stage: build
  image: node:18
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - public/build/

Gyakori buktatók és tanulságok

A tapasztalatom szerint három fő hibát szoktak elkövetni a CI bevezetésekor:

1. Túl korán akarják a tökéletes folyamatot Ne akarjatok egyből 100%-os tesztlefedettséget és mindenféle komplex ellenőrzést. Kezdjetek egyszerűen: egy linting és pár alapvető teszt is óriási előrelépés.

2. Lokális és CI környezet eltérése A klasszikus: „Nálam működik!” Ha a tesztek máshogy futnak lokálisan és a CI szerveren, az általában környezeti változók, adatbázis eltérések vagy cache problémák miatt van. Docker segítheg ezen.

3. Túl lassú folyamat Ha egy CI futtatás 30 percig tart, senki sem fogja szeretni. Párhuzamosítsátok a feladatokat, és csak a szükséges lépéseket végezzétek. Például ne futtassátok újra az asset buildelést, ha csak backend kód változott.

Egy PHP példa a gyakorlatból

Nézzünk egy konkrét esetet, amikor a CI megment minket egy hülye hibától. Tegyük fel, hogy van egy User osztályunk:

<?php

class User {
    private $email;
    
    public function setEmail(string $email): void {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Érvénytelen email cím');
        }
        $this->email = $email;
    }
    
    public function getEmail(): string {
        return $this->email;
    }
}

És hozzá egy egyszerű teszt:

<?php

use PHPUnit\Framework\TestCase;

class UserTest extends TestCase {
    public function testValidEmailIsAccepted(): void {
        $user = new User();
        $user->setEmail('teszt@example.com');
        $this->assertEquals('teszt@example.com', $user->getEmail());
    }
    
    public function testInvalidEmailThrowsException(): void {
        $this->expectException(InvalidArgumentException::class);
        $user = new User();
        $user->setEmail('érvénytelen-email');
    }
}

Ha valaki megváltoztatja a setEmail metódust úgy, hogy ne ellenőrizze az email címet, a CI azonnal jelezni fogja, hogy a teszt elbukott.

Frontend rész: jQuery és Bootstrap világban

A frontend oldalon is hasonlóan fontosak az ellenőrzések. Például egy jQuery kódrészlet, ami könnyen elfelejtheti a hibakezelést:

// Rossz példa - nincs hibakezelés
$(document).ready(function() {
    $('#userForm').submit(function(e) {
        e.preventDefault();
        $.ajax({
            url: '/api/save-user',
            method: 'POST',
            data: $(this).serialize(),
            success: function(response) {
                $('#result').html('Sikeres mentés!');
            }
            // Hiányzik: error callback!
        });
    });
});

// Javított változat
$(document).ready(function() {
    $('#userForm').submit(function(e) {
        e.preventDefault();
        var $form = $(this);
        var $result = $('#result');
        
        $.ajax({
            url: '/api/save-user',
            method: 'POST',
            data: $form.serialize(),
            success: function(response) {
                $result.removeClass('alert-danger').addClass('alert-success')
                      .html('Sikeres mentés!').show();
            },
            error: function(xhr) {
                $result.removeClass('alert-success').addClass('alert-danger')
                      .html('Hiba történt: ' + xhr.responseText).show();
            }
        });
    });
});

Egy jó CI folyamat tartalmazhat ESLint konfigurációt, ami figyelmeztet, ha hiányzik az error kezelés, vagy ha nem megfelelő a kódstílus.

React és Python: mikor érdemes bevonni?

React komponensek esetén különösen értékes a CI, mert a típusellenőrzés (TypeScript vagy PropTypes) és a komponens tesztek (Jest + React Testing Library) rengeteg hibát kiszűrhetnek. De ha a projektetek főleg PHP és jQuery/Bootstrap, ne kényszerítsétek be a Reactet csak divatból.

Pythonra általában akkor érdemes váltani a CI folyamatban, ha valamilyen specifikus scriptet írtok hozzá (pl. adatfeldolgozás, ML modell), vagy ha a projektetek backendje Pythonban íródott. PHP projektnél maradjatok a PHP-nél.

Összegzés

A CI folyamat nem varázslat, hanem egy stratégiai befektetés a kódminőségbe és a fejlesztők mentális egészségébe. Az első beállítás pár órát igénybe vehet, de hosszú távon rengeteget takarít meg a debuggingból, a „nálam működik” beszélgetésekből és az éjszakai deploy pánikból.

Ne azzal kezdjétek, hogy minden tökéletes legyen. Kezdjetek egy egyszerű lintinggel és egy-két alapteszttel, majd fokozatosan bővítsétek. Hamarosan észreveszitek, hogy mennyivel magabiztosabban tudtok változtatásokat eszközölni, és mennyivel kevesebb a „jaj, elrontottam valamit” érzés.

Végső soron a legjobb CI folyamat az, amit tényleg használtok, nem az, ami mindent ellenőriz, de annyira lassú, hogy mindenki kikerüli.