Blog JSystems - uwalniamy wiedzę!

Szukaj
Animowany przepływ pracy testera z AI: od wymagań przez przypadki testowe, testy i CI/CD aż po raport
Cały przepływ, który rozbijemy w tym artykule: z wymagań AI pomaga zrobić przypadki testowe i dane, potem uruchamiamy testy (API, frontend, wydajność, bezpieczeństwo), a CI/CD odpala je przy każdej zmianie.

Testowanie to zawód, w którym sztuczna inteligencja nie zastępuje człowieka, tylko zdejmuje z niego najżmudniejszą część roboty. Zamiast rozpisywać dziesiątki przypadków testowych ręcznie, opisujesz funkcję i dostajesz gotowy szkielet do sprawdzenia. Zamiast wymyślać dane testowe, generujesz je jednym poleceniem. W tym artykule przejdziemy przez cały warsztat testera wspieranego przez AI - i co ważne, każdy przykład uruchomiliśmy naprawdę, na jednej małej aplikacji, której kod możesz sobie pobrać.

Pokażemy, jak AI pomaga w testach manualnych, w dokumentacji, w testach API (Postman), we frontendzie (Cypress), w testach wydajnościowych (k6 i Artillery), w bezpieczeństwie (OWASP ZAP) oraz we wpięciu tego wszystkiego w potok CI/CD - mechanizm, który automatycznie uruchamia testy przy każdej zmianie w kodzie. Na koniec zbudujemy małe własne narzędzie i omówimy, jak korzystać z AI bezpiecznie, bez wyciekania firmowych danych.

Z tego artykułu dowiesz się:

Gdzie AI realnie pomaga testerowi

Zacznijmy od mapy. AI nie jest jednym magicznym przyciskiem - wchodzi do pracy testera w kilku konkretnych miejscach. W jednych zaoszczędzi Ci godziny (generowanie przypadków i danych), w innych podpowie składnię narzędzia albo wytłumaczy niezrozumiały wynik. W każdym z tych obszarów zasada jest ta sama: AI proponuje, a Ty weryfikujesz.

Infografika ośmiu obszarów, w których AI pomaga testerowi: testy manualne, API, E2E, wydajność, bezpieczeństwo, CI/CD, własne narzędzia, dokumentacja
Osiem obszarów pracy testera, w których AI daje realny zysk. Wszystkie po kolei przechodzimy w tym artykule na żywej aplikacji.

Nasze środowisko: mały sklep do testowania

Żeby przykłady były prawdziwe, a nie rysowane, postawiliśmy niewielką aplikację - Sklepik. To zwykły serwer w Node.js: kilka adresów API (lista produktów, szczegóły produktu, logowanie, składanie zamówienia) oraz dwie strony (lista produktów i formularz zamówienia). Wszystkie narzędzia w tym artykule celują właśnie w tę aplikację. Kod możesz pobrać i uruchomić u siebie w dwóch komendach.

git clone https://github.com/konwertyta/sklepik-ai-dla-testerow
cd sklepik-ai-dla-testerow
npm install
npm start   # http://localhost:3100
Celowy błąd w środku. Aplikacja ma jedną ukrytą usterkę: przy składaniu zamówienia nie sprawdza, czy ilość jest większa od zera. Zamówienie na 0 sztuk zostaje przyjęte z sumą 0 zł. Ten błąd odkryjemy później testem, który podpowie nam AI - bez zaglądania do kodu.

Oto fragment obsługi zamówienia. Widać, że jest walidacja stanu magazynowego, ale brakuje sprawdzenia samej ilości:

app.post('/api/orders', (req, res) => {
  const { productId, qty } = req.body || {};
  const p = products.find(x => x.id === Number(productId));
  if (!p) return res.status(404).json({ error: 'not_found' });
  // brak walidacji qty > 0 - tutaj chowa się błąd
  if (p.stock < qty) return res.status(409).json({ error: 'out_of_stock' });
  const order = { id: ++orderSeq, productId: p.id, qty: Number(qty),
                  total: Math.round(p.price * Number(qty) * 100) / 100 };
  res.status(201).json(order);
});

Testy manualne: przypadki i dane testowe z AI

Najczęstsze codzienne zadanie testera to zamiana wymagania na listę przypadków testowych. To wdzięczna robota dla AI, bo modele świetnie wypisują warianty pozytywne, negatywne i brzegowe - czyli te na granicy dozwolonych wartości, jak zero czy maksimum. Wklejamy kryteria akceptacji naszej funkcji zamówienia i prosimy o tabelę przypadków. Prompt, którego użyliśmy:

Te trzy rodzaje przypadków testowych warto rozróżniać, bo sprawdzają aplikację z zupełnie różnych stron:

  • Pozytywny - poprawne dane i typowe użycie, czyli tak zwana szczęśliwa ścieżka. Sprawdzamy, czy przy dobrych danych aplikacja robi to, co powinna (na przykład przyjmuje zamówienie na 2 sztuki i pokazuje sumę).
  • Negatywny - świadomie błędne dane. Sprawdzamy, czy aplikacja poprawnie odmawia (na przykład ujemna ilość albo tekst zamiast liczby - zamówienie ma zostać odrzucone z czytelnym komunikatem).
  • Brzegowy - wartości na samej granicy dozwolonego zakresu: zero, jeden, maksimum, dokładnie stan magazynu i stan powiększony o jeden. To najmniej intuicyjny, a zarazem najważniejszy rodzaj, bo właśnie na krawędziach najczęściej chowają się błędy - programista zwykle sprawdza „środek" zakresu, a nie jego brzegi. W naszej aplikacji błąd siedzi dokładnie na brzegu: przy ilości równej zero.
Jesteś doświadczonym testerem QA. Na podstawie poniższych kryteriów akceptacji wypisz przypadki testowe (pozytywne, negatywne i brzegowe) w tabeli z kolumnami: Nazwa | Kroki | Oczekiwany wynik. Funkcja: składanie zamówienia w sklepie internetowym. Kryteria akceptacji: - użytkownik wybiera produkt z listy i podaje ilość, - po kliknięciu Złóż zamówienie system tworzy zamówienie i pokazuje jego numer oraz sumę, - ilość musi być liczbą większą od zera, - nie można zamówić więcej sztuk niż jest w magazynie.

ChatGPT zwrócił komplet przypadków w tabeli. Zwróć uwagę na wiersz Negatywny - ilość 0: model sam zaproponował ten przypadek brzegowy, który za chwilę wykryje realny błąd w naszej aplikacji.

Tabela przypadków testowych wygenerowana przez ChatGPT dla funkcji składania zamówienia, z kolumnami Nazwa, Kroki, Oczekiwany wynik
Odpowiedź ChatGPT: przypadki pozytywne, brzegowe i negatywne dla składania zamówienia. Każdy ma kroki i oczekiwany wynik - gotowe do wykonania albo do przepisania na test automatyczny.

Drugie zadanie to dane testowe. Zamiast wymyślać dziesiątki fikcyjnych klientów, generujemy je z AI. W czacie robimy to raz, na kolanie, ale jeśli chcemy odświeżać dane przy każdym uruchomieniu testów, lepiej zamknąć to w małym skrypcie. Napisaliśmy w Pythonie plik generate_testdata.py, który wysyła jedno zapytanie do API modelu i wypisuje gotowy JSON - ten sam efekt co w czacie, tyle że powtarzalny i bez ręcznego kopiowania. Oto cały skrypt:

import json, re, urllib.request

KEY = open("openai_key.txt").read().strip()          # Twój klucz API

PROMPT = ("Wygeneruj 6 realistycznych rekordów klientów do testów sklepu internetowego. "
          "Zwróć wyłącznie poprawny JSON - tablicę obiektów z polami: "
          "imie, nazwisko, email, telefon, miasto, kod_pocztowy.")

body = {"model": "gpt-4o-mini", "messages": [{"role": "user", "content": PROMPT}]}
req = urllib.request.Request(
    "https://api.openai.com/v1/chat/completions",
    data=json.dumps(body).encode(),
    headers={"Authorization": "Bearer " + KEY, "Content-Type": "application/json"},
)
resp = json.load(urllib.request.urlopen(req))

content = resp["choices"][0]["message"]["content"].strip()
content = re.sub(r"^```(?:json)?\s*|\s*```$", "", content)   # zdejmij ramki markdown
print(content)

Uruchamiamy go w terminalu poleceniem python generate_testdata.py i dostajemy komplet rekordów w formacie JSON, z poprawnymi polskimi znakami w danych:

Terminal z wynikiem skryptu w Pythonie generującego dane testowe klientów w formacie JSON przez API modelu językowego
Skrypt woła model przez API i dostaje gotowy JSON z danymi testowymi. Taki krok można wpiąć w potok CI, żeby dane były świeże przy każdym przebiegu testów.

Sercem skryptu jest prompt (zmienna PROMPT w kodzie powyżej) - im węższe i bardziej konkretne polecenie, tym mniej model zmyśla:

Wygeneruj 6 realistycznych rekordów klientów do testów sklepu internetowego. Zwróć wyłącznie poprawny JSON - tablicę obiektów z polami: imie, nazwisko, email, telefon, miasto, kod_pocztowy.

Dokumentacja: plan i strategia testów w minutę

Plan testów czy strategia to dokumenty, które łatwo odkładać na później. AI robi z nich szkic w kilka sekund - a Ty tylko poprawiasz i dopasowujesz do projektu. Poprosiliśmy o zwięzły plan testów dla Sklepiku:

Jako inżynier QA przygotuj zwięzły plan testów dla aplikacji sklepu internetowego Sklepik (przeglądanie produktów, składanie zamówień, logowanie). Uwzględnij: cel i zakres, rodzaje testów (manualne, API, E2E, wydajnościowe, bezpieczeństwa), środowisko testowe, kryteria wejścia i wyjścia oraz najważniejsze ryzyka. Odpowiedz zwięźle w punktach, po polsku.
Plan testów aplikacji Sklepik wygenerowany przez ChatGPT: cel i zakres, rodzaje testów, środowisko, kryteria wejścia i wyjścia oraz ryzyka
Szkic planu testów z AI: cel i zakres, rodzaje testów z nazwami narzędzi, środowisko, kryteria wejścia i wyjścia oraz ryzyka. Punkt wyjścia do własnego dokumentu, nie gotowiec do wklejenia w ciemno.
Zawsze czytaj, co dostajesz. Plan z AI bywa ogólny i czasem wpisze coś, czego w projekcie nie ma. Traktuj go jak szkic od młodszego kolegi: dobra baza, ale odpowiadasz Ty.

Testy API: Postman i Newman

Adres API (endpoint - pojedynczy punkt, pod który wysyłamy zapytanie, np. lista produktów) testuje się w Postmanie: wysyłamy zapytanie i sprawdzamy odpowiedź asercjami. Asercja to warunek, który musi być spełniony, na przykład status odpowiedzi równy 200. AI - w Postmanie nazywa się to Postbot - potrafi wygenerować te asercje za nas. Wystarczy pokazać odpowiedź i powiedzieć, co ma sprawdzić:

Napisz testy do tej odpowiedzi w składni Postmana (pm.test): sprawdź status 200, że pole count wynosi 6 oraz że items jest tablicą obiektów mających pola name i price.

Efekt to gotowy kod do zakładki Tests. Piszemy go raz, a wykonuje się przy każdym uruchomieniu kolekcji:

// Zakładka "Tests" w Postmanie - asercje, które podpowiada Postbot:
pm.test("status 200", () => pm.response.to.have.status(200));

const body = pm.response.json();
pm.test("zwraca 6 produktów", () => pm.expect(body.count).to.eql(6));
pm.test("items to tablica", () => pm.expect(body.items).to.be.an("array"));
pm.test("pierwszy produkt ma nazwę i cenę", () => {
  pm.expect(body.items[0]).to.have.property("name");
  pm.expect(body.items[0]).to.have.property("price");
});

Kolekcję Postmana da się uruchomić z linii poleceń narzędziem Newman - to ten sam plik kolekcji, tylko odpalany bez klikania. Dzięki temu te same testy API wpniemy później w potok CI. Oto realny wynik: sześć zapytań, dwanaście asercji, wszystkie zielone.

Terminal z wynikiem newman run: sześć zapytań do API Sklepiku, dwanaście asercji zaliczonych, w tym testy negatywne 401 i 404
Realne uruchomienie kolekcji Postmana przez Newman. Widać testy pozytywne (200, 201) i negatywne (poprawne 401 i 404). Dwanaście asercji, zero błędów.

Testy frontendu (E2E): Cypress

Test E2E, czyli od początku do końca, udaje prawdziwego użytkownika: otwiera stronę, klika, wpisuje, sprawdza wynik. Piszemy je w Cypressie. AI dobrze radzi sobie z takim szkieletem - podajemy nazwy pól formularza i opis scenariuszy, a dostajemy gotowy test. Ważne, żeby w prompcie podać konkretne selektory - sposób wskazania elementu na stronie. U nas są to atrybuty data-cy, czyli zwykłe atrybuty HTML dodane w kodzie strony specjalnie na potrzeby testów (np. data-cy="qty" przy polu ilości). Test trzyma się takiego stabilnego znacznika zamiast kruchych klas CSS czy tekstu przycisku, które przy przebudowie wyglądu strony często się zmieniają i psują testy:

Napisz test E2E w Cypress dla formularza zamówienia. Pola mają atrybuty data-cy: product (lista), qty (ilość), order-btn (przycisk), result (komunikat). Dodaj przypadek pozytywny (zamówienie 2 sztuk) oraz przypadek brzegowy dla ilości 0.

Test, który dostaliśmy, ma trzy przypadki: dwie ścieżki, które powinny przejść (zamówienie 2 i 3 sztuk), oraz przypadek brzegowy z ilością 0, który świadomie zakłada, że aplikacja powinna zero odrzucić:

describe('Sklepik - składanie zamówienia', () => {
  beforeEach(() => cy.visit('/sklep.html'));

  it('ścieżka pozytywna: składa zamówienie na 2 sztuki', () => {
    cy.get('[data-cy=product]').select(0);
    cy.get('[data-cy=qty]').clear().type('2');
    cy.get('[data-cy=order-btn]').click();
    cy.get('[data-cy=result]').should('be.visible').and('contain', 'przyjęte');
  });

  it('inna ilość: zamówienie na 3 sztuki przechodzi', () => {
    cy.get('[data-cy=qty]').clear().type('3');
    cy.get('[data-cy=product]').select(1);
    cy.get('[data-cy=order-btn]').click();
    cy.get('[data-cy=result]').should('contain', 'przyjęte');
  });

  it('przypadek brzegowy: ilość 0 powinna zostać odrzucona', () => {
    cy.get('[data-cy=qty]').clear().type('0');
    cy.get('[data-cy=order-btn]').click();
    cy.get('[data-cy=result]').should('contain', 'Błąd');   // ten test wykryje błąd
  });
});

Uruchamiamy testy komendą npx cypress run. I tu dzieje się najciekawsze: dwa testy przechodzą, a trzeci - ten brzegowy - czerwony.

Terminal Cypress: dwa testy zielone, jeden czerwony - przypadek brzegowy ilości 0 wykrył błąd aplikacji
Wynik npx cypress run: dwa testy przechodzą, trzeci (ilość 0) failuje. Cypress oczekiwał komunikatu błędu, a aplikacja zamówienie przyjęła.

Cypress przy każdej awarii sam zapisuje zrzut ekranu z momentu błędu. Widać na nim, co poszło nie tak: formularz z ilością 0 zwrócił zielony komunikat "Zamówienie przyjęte" z sumą 0 zł. To dokładnie ten ukryty błąd z kodu, który pokazaliśmy na początku - i znalazł go przypadek testowy podpowiedziany przez AI, bez zaglądania do źródeł.

Zrzut awarii Cypress: po lewej nieudana asercja testu, po prawej aplikacja Sklepik przyjmująca zamówienie na 0 sztuk za 0 zł
Zrzut zapisany automatycznie przez Cypress w chwili błędu. Po prawej aplikacja przyjmuje zamówienie na 0 sztuk (suma 0 zł) - to potwierdza brak walidacji ilości.

Testy wydajnościowe: k6 i Artillery

Test wydajnościowy sprawdza, jak aplikacja znosi obciążenie: wielu użytkowników naraz, przez jakiś czas. Dwa popularne, darmowe narzędzia to k6 (skrypty w JavaScript) i Artillery (scenariusze w YAML - prostym formacie tekstowym, bez pisania kodu). AI pomaga napisać skrypt, dobrać progi i - co równie ważne - zrozumieć wynik.

k6

W k6 opisujemy etapy obciążenia (rozgrzewka, utrzymanie, wygaszanie) i progi - po angielsku thresholds, czyli granice, po przekroczeniu których test uznajemy za nieudany. Nasz skrypt strzela w listę produktów i pilnuje, żeby 95% zapytań zmieściło się poniżej 300 milisekund:

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '10s', target: 20 },  // rozgrzewka do 20 wirtualnych użytkowników
    { duration: '20s', target: 20 },  // utrzymanie obciążenia
    { duration: '10s', target: 0 },   // wygaszanie
  ],
  thresholds: {
    http_req_duration: ['p(95)<300'], // 95% zapytań poniżej 300 ms
  },
};

export default function () {
  const res = http.get('http://localhost:3100/api/products');
  check(res, {
    'status 200': (r) => r.status === 200,
    'zwraca 6 produktów': (r) => r.json('count') === 6,
    'czas < 300 ms': (r) => r.timings.duration < 300,
  });
  sleep(1);
}
Terminal k6 z podsumowaniem testu wydajnościowego API Sklepiku: wszystkie progi zielone, 95. percentyl czasu odpowiedzi około 3 ms, 610 zapytań bez błędu
Podsumowanie k6: wszystkie progi na zielono - 95. percentyl czasu odpowiedzi to około 3 ms (przy progu 300 ms), zero błędów na 610 zapytań. Lokalne API Sklepiku bez trudu wyrabia się pod obciążeniem 20 równoczesnych użytkowników.

Tym razem wszystkie progi przeszły - lokalne API odpowiada w kilka milisekund, więc ani czas, ani liczba błędów nie zbliżyły się do granicy. Gdyby jednak któryś próg zaświecił się na czerwono (wolniejszy backend, więcej użytkowników, cięższe zapytania), to właśnie w interpretacji takiego raportu AI pomaga najbardziej: podpowie, czy to realny problem, czy naturalny skok pod obciążeniem.

Artillery

Artillery opisuje to samo bez pisania kodu - w pliku YAML podajemy fazy obciążenia i przepływ: wejdź na listę produktów, potem złóż zamówienie:

config:
  target: "http://localhost:3100"
  phases:
    - duration: 20
      arrivalRate: 5
      name: "Rozgrzewka"
    - duration: 20
      arrivalRate: 20
      name: "Szczyt obciążenia"
scenarios:
  - name: "Przeglądanie i zamówienie"
    flow:
      - get:
          url: "/api/products"
          capture:
            - json: "$.items[0].id"
              as: "pid"
      - post:
          url: "/api/orders"
          json: { productId: "{{ pid }}", qty: 1 }
          expect:
            - statusCode: 201
Terminal Artillery z raportem testu obciążeniowego: tysiąc zapytań, rozkład kodów 200 i 201, czasy odpowiedzi i brak błędów
Raport Artillery: 1000 zapytań (500 razy 200 i 500 razy 201), zero błędów, czasy odpowiedzi w milisekundach. Scenariusz przeszedł przez obie fazy obciążenia.

Które wybrać? k6 daje wygodne progi w kodzie i świetne percentyle, Artillery kusi prostotą YAML-a. W skrócie:

Infografika porównująca k6 i Artillery: k6 to skrypty JavaScript z progami, Artillery to scenariusze YAML bez kodu
k6 kontra Artillery. Oba obejmujemy na tej samej aplikacji - wybór zależy od tego, czy wolisz pisać skrypty, czy opisywać scenariusze w YAML.

Bezpieczeństwo: skan OWASP ZAP

Testów bezpieczeństwa nie robi się na oko. OWASP ZAP to darmowe narzędzie, które samo przechodzi po aplikacji i szuka typowych słabości. Najprostszy tryb to skan pasywny - po angielsku baseline, czyli podstawowy przegląd bez atakowania aplikacji. Uruchamiamy go jedną komendą w kontenerze Docker, wskazując adres naszej strony. Wynik to lista ostrzeżeń - u nas osiem, głównie brakujące nagłówki bezpieczeństwa:

Terminal OWASP ZAP z wynikiem skanu baseline aplikacji Sklepik: osiem ostrzeżeń o brakujących nagłówkach bezpieczeństwa, 59 testów zaliczonych
Skan pasywny ZAP: osiem ostrzeżeń (brak nagłówków CSP, X-Content-Type-Options, Permissions-Policy i innych), żadnego błędu krytycznego, 59 testów zaliczonych.

ZAP tworzy też czytelny raport HTML z podziałem na poziomy ryzyka. To dobry materiał do przekazania zespołowi deweloperskiemu:

Raport HTML OWASP ZAP z podsumowaniem alertów według poziomu ryzyka: trzy średniego i sześć niskiego ryzyka dla aplikacji Sklepik
Raport HTML z ZAP: podsumowanie alertów według ryzyka (średnie, niskie) plus szczegóły każdej podatności. Gotowe do załączenia w zgłoszeniu błędu.

Tu AI pokazuje inną mocną stronę - tłumaczenie. Zamiast googlać każdy skrót, wklejamy listę ostrzeżeń i prosimy o wyjaśnienie oraz priorytety:

Poniżej wynik skanu OWASP ZAP mojej aplikacji webowej (lista ostrzeżeń z brakującymi nagłówkami bezpieczeństwa). Wyjaśnij po polsku, co oznacza każde z nich, które są najważniejsze i jak je naprawić. Uszereguj od najpilniejszych.
Odpowiedź ChatGPT wyjaśniająca po polsku osiem ostrzeżeń OWASP ZAP z aplikacji Sklepik: znaczenie każdego brakującego nagłówka, sposób naprawy i kolejność priorytetów
Odpowiedź ChatGPT: każde z ośmiu ostrzeżeń ZAP wyjaśnione prostym językiem - co oznacza, jak je naprawić i od czego zacząć. Zamiast wyszukiwać każdy skrót osobno, dostajesz gotową kolejność działań (na początek CSP i ochrona przed clickjackingiem).
Uwaga na dane wrażliwe. Wynik skanu bywa nieszkodliwy, ale realnych logów, zrzutów z produkcji czy fragmentów kodu klienta nie wklejaj do publicznego czatu. Wracamy do tego w sekcji o bezpiecznym użyciu AI.

CI/CD: testy przy każdej zmianie

Największy zysk z testów automatycznych przychodzi wtedy, gdy uruchamiają się same - przy każdym wgraniu zmiany do repozytorium. To właśnie CI/CD: potok, który buduje aplikację i odpala testy. Napiszemy prosty potok dla GitHub Actions, który instaluje zależności, uruchamia aplikację i odpala nasze testy API przez Newman. Plik zapisujemy w repozytorium pod ścieżką .github/workflows/ci.yml - GitHub sam skanuje katalog .github/workflows/ i każdy plik YAML w środku traktuje jako osobny potok. AI świetnie podpowiada te pliki konfiguracyjne, bo ich składnia jest powtarzalna:

name: Testy Sklepiku
on: [push]
jobs:
  testy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm install
      - name: Start aplikacji w tle
        run: |
          node server.js &
          npx wait-on http://localhost:3100/api/health
      - name: Testy API (Newman)
        run: |
          npm install -g newman
          newman run postman/sklepik_collection.json

Po wgraniu tego pliku do repozytorium (klasyczne git add, git commit i git push) GitHub sam wykrywa nowy potok i uruchamia go - u nas przy każdym pushu, bo w sekcji on: [push] tak ustawiliśmy. Nie trzeba nic klikać w interfejsie. Poniżej realny przebieg w naszym repozytorium - wszystko na zielono:

Zrzut GitHub Actions z udanym przebiegiem potoku CI dla repozytorium Sklepik: status Success, zadanie testy zaliczone
Realny przebieg GitHub Actions w publicznym repozytorium demo. Potok zainstalował zależności, wystartował aplikację i uruchomił testy API - status Success.

Ta sama idea działa na innych platformach. Na GitLabie plik nazywa się .gitlab-ci.yml i leży w głównym katalogu repozytorium (GitLab CI/CD wykrywa go automatycznie):

stages: [test]

testy-api:
  stage: test
  image: node:20
  script:
    - npm install
    - node server.js &
    - npx wait-on http://localhost:3100/api/health
    - npm install -g newman
    - newman run postman/sklepik_collection.json

A na Bitbuckecie - bitbucket-pipelines.yml, również w katalogu głównym (Pipelines trzeba raz włączyć w ustawieniach repozytorium):

image: node:20
pipelines:
  default:
    - step:
        name: Testy API
        script:
          - npm install
          - node server.js &
          - npx wait-on http://localhost:3100/api/health
          - npm install -g newman
          - newman run postman/sklepik_collection.json

Własne narzędzia: DeadLink checker

Czasem najszybszym testem jest mały skrypt napisany na miarę. Klasyczny przykład to sprawdzarka martwych linków (DeadLink checker): pobiera stronę, wyciąga wszystkie odnośniki i sprawdza, które prowadzą donikąd. Kiedyś pisało się to pół godziny; z AI powstaje w minutę. Prompt:

Napisz skrypt w Pythonie (tylko biblioteka standardowa), który pobiera podaną stronę, wyciąga wszystkie linki i sprawdza, które zwracają błąd 4xx/5xx albo nie odpowiadają. Dla każdego linku wypisz kod HTTP, status i adres.

Dostajemy kompletny, działający skrypt - tu w Pythonie, bez żadnych dodatkowych bibliotek:

import sys, re, urllib.request, urllib.parse
from urllib.error import HTTPError, URLError

start = sys.argv[1]
html = urllib.request.urlopen(start, timeout=10).read().decode("utf-8", "replace")

seen, results = set(), []
for href in re.findall(r'href="([^"#]+)"', html):
    url = urllib.parse.urljoin(start, href)
    if url in seen:
        continue
    seen.add(url)
    try:
        code = urllib.request.urlopen(url, timeout=10).status
        status = "OK"
    except HTTPError as e:
        code, status = e.code, "MARTWY"
    except URLError as e:
        code, status = "-", f"MARTWY ({e.reason})"
    results.append((code, status, url))

print(f"Sprawdzono {len(results)} linków na stronie {start}\n")
print(f"{'KOD':>4}  {'STATUS':<26} URL")
print("-" * 76)
for code, status, url in results:
    print(f"{str(code):>4}  {status:<26} {url}")

dead = [r for r in results if r[1].startswith("MARTWY")]
print(f"\nMartwe linki: {len(dead)} / {len(results)}")

Uruchamiamy go na stronie głównej Sklepiku, w której celowo zostawiliśmy kilka martwych linków, i od razu widać wynik:

Terminal ze skryptem DeadLink checker w Pythonie, który wykrył trzy martwe linki na stronie Sklepiku (dwa 404 i jeden bez odpowiedzi DNS)
Własny DeadLink checker w akcji: z ośmiu linków trzy są martwe - dwie podstrony zwracają 404, a jeden zewnętrzny adres w ogóle nie odpowiada.

Ten sam schemat - poproś AI o mały skrypt, uruchom, sprawdź - działa dla dziesiątek drobnych zadań: sprawdzania statusów odpowiedzi, porównywania plików, generowania raportów. To najprostszy sposób, żeby zacząć programować z AI, a od tego już krok do poważniejszej automatyzacji.

Piramida testów a rola AI

Na koniec warto ułożyć to w całość. Klasyczna piramida testów mówi, że najwięcej powinno być szybkich testów niższego poziomu, a najmniej wolnych testów przez interfejs. AI pomaga na każdym piętrze, ale największy zysk daje na dole - tam, gdzie testów jest najwięcej i gdzie generowanie ich ręcznie boli najbardziej.

Infografika piramidy testów z rolą AI: u dołu testy jednostkowe, w środku integracyjne i API, u góry E2E - AI wspiera każdy poziom
Piramida testów: im niżej, tym więcej testów i tym szybciej dowozi je AI. Na górze (E2E) AI daje szkielet, ale to Ty pilnujesz, że test sprawdza właściwą rzecz.

Bezpieczne użycie AI w testowaniu

Skoro AI ma tyle zalet, gdzie jest haczyk? W dwóch miejscach, o których trzeba pamiętać od pierwszego dnia.

Po pierwsze - dane. Do publicznego czatu nie wkleja się danych produkcyjnych, prawdziwych danych osobowych, wewnętrznych logów ani fragmentów kodu klienta. To kwestia i przepisów (RODO), i umów (NDA). Jeśli musisz pracować na wrażliwych danych, wybierz wersję firmową modelu z gwarancją, że dane nie są używane do uczenia, albo model uruchomiony lokalnie, u siebie. Do testów w zupełności wystarczają dane wymyślone - takie jak te, które sami wygenerowaliśmy.

Po drugie - zaufanie. AI halucynuje: potrafi wymyślić nieistniejący adres API, zły selektor albo asercję, która zawsze przechodzi i niczego nie sprawdza. Dlatego każdy wygenerowany test trzeba uruchomić i zobaczyć, czy naprawdę bada to, co powinien. Zasada z całego artykułu wraca tu ostatni raz: AI generuje, człowiek weryfikuje. W tym układzie tester nie znika - staje się autorem i recenzentem, który robi więcej w krótszym czasie.

Podsumowanie

Przeszliśmy cały warsztat: od przypadków i danych testowych, przez dokumentację, testy API i frontendu, wydajność i bezpieczeństwo, aż po CI/CD i własne narzędzia. W każdym z tych miejsc AI zdjęła z nas część zmudnej roboty, a my zachowaliśmy kontrolę nad tym, co i jak jest testowane. Najlepiej przećwiczyć to na własnej skórze - pobierz kod Sklepiku, odtwórz przykłady i zobacz, ile udaje się zrobić szybciej.

Jeśli chcesz przejść przez to z trenerem-praktykiem, na żywo i na realnych przykładach, przygotowaliśmy szkolenie skrojone dokładnie pod ten zakres.

Baner szkolenia AI dla testerów JSystems z terminami gwarantowanymi

Szkolenie AI dla testerów -->

×

Komentarze (0)

Musisz być zalogowany by móc dodać komentarz. Zaloguj się przez Google

Brak komentarzy...