Generowanie testów
AI pisze kompleksowe zestawy testów
Przekształć testowanie z obowiązku w supermoce. Naucz się wzorców opartych na AI, które generują kompleksowe zestawy testów, utrzymują je automatycznie i wyłapują błędy przed produkcją.
Tradycyjne wyzwania testowania:
Korzyści testowania wspomaganego przez AI:
Wpływ: Osiągnij 80%+ pokrycia testami 10x szybciej wyłapując 3x więcej błędów.
Generowanie testów
AI pisze kompleksowe zestawy testów
Odkrywanie przypadków brzegowych
Znajdź scenariusze których nie rozważałeś
Utrzymanie testów
Utrzymuj testy w synchronizacji ze zmianami kodu
Optymalizacja pokrycia
Inteligentnie celuj w nietestowany kod
Przeanalizuj kod
// Funkcja docelowaexport async function processPayment(order, paymentMethod) { if (!order || !order.total) { throw new Error('Nieprawidłowe zamówienie'); }
if (order.total <= 0) { throw new Error('Kwota zamówienia musi być dodatnia'); }
if (!isValidPaymentMethod(paymentMethod)) { throw new Error('Nieprawidłowa metoda płatności'); }
const result = await paymentGateway.charge({ amount: order.total, currency: order.currency || 'USD', method: paymentMethod });
if (result.success) { await updateOrderStatus(order.id, 'paid'); await sendConfirmationEmail(order.customerEmail); }
return result;}
Poproś o kompleksowe testy
@file payment.js
Wygeneruj kompleksowe testy dla processPayment obejmujące:1. Scenariusze szczęśliwych ścieżek2. Wszystkie warunki błędów3. Przypadki brzegowe4. Zachowanie asynchroniczne5. Mock zewnętrznych zależności6. Testuj awarie bramy płatniczej7. Weryfikuj wszystkie efekty uboczne
AI generuje kompletny zestaw testów
describe('processPayment', () => { let mockPaymentGateway; let mockUpdateOrderStatus; let mockSendConfirmationEmail;
beforeEach(() => { // AI konfiguruje wszystkie niezbędne mocki mockPaymentGateway = { charge: jest.fn() }; mockUpdateOrderStatus = jest.fn(); mockSendConfirmationEmail = jest.fn(); });
describe('szczęśliwa ścieżka', () => { it('powinien przetworzyć prawidłową płatność pomyślnie', async () => { const order = { id: '123', total: 99.99, customerEmail: 'test@example.com' };
mockPaymentGateway.charge.mockResolvedValue({ success: true, transactionId: 'tx-123' });
const result = await processPayment(order, 'credit_card');
expect(mockPaymentGateway.charge).toHaveBeenCalledWith({ amount: 99.99, currency: 'USD', method: 'credit_card' });
expect(mockUpdateOrderStatus).toHaveBeenCalledWith('123', 'paid'); expect(mockSendConfirmationEmail).toHaveBeenCalledWith('test@example.com'); expect(result.success).toBe(true); });
it('powinien obsłużyć niestandardową walutę', async () => { // AI generuje test waluty }); });
describe('warunki błędów', () => { it('powinien rzucić błąd dla brakującego zamówienia', async () => { await expect(processPayment(null, 'credit_card')) .rejects.toThrow('Nieprawidłowe zamówienie'); });
it('powinien rzucić błąd dla zerowej kwoty', async () => { const order = { id: '123', total: 0 }; await expect(processPayment(order, 'credit_card')) .rejects.toThrow('Kwota zamówienia musi być dodatnia'); });
// AI generuje wszystkie inne scenariusze błędów });
describe('przypadki brzegowe', () => { it('powinien obsłużyć timeout bramy płatniczej', async () => { // AI tworzy scenariusz timeout });
it('powinien obsłużyć równoczesne płatności', async () => { // AI tworzy test warunków wyścigu }); });});
// Krok 1: Opisz co chcesz/** * @cursor Utwórz funkcję która: * - Waliduje adresy email * - Zwraca znormalizowany email (małe litery, przycięty) * - Obsługuje subadresowanie (user+tag@example.com) * - Waliduje przeciwko typowym błędom * * Napisz testy pierwsze, potem implementację */
// AI generuje testydescribe('validateEmail', () => { it('powinien walidować poprawne emaile', () => { expect(validateEmail('user@example.com')).toBe('user@example.com'); expect(validateEmail('USER@EXAMPLE.COM')).toBe('user@example.com'); expect(validateEmail(' user@example.com ')).toBe('user@example.com'); });
it('powinien obsłużyć subadresowanie', () => { expect(validateEmail('user+tag@example.com')).toBe('user@example.com'); expect(validateEmail('user+newsletter@gmail.com')).toBe('user@gmail.com'); });
it('powinien odrzucić nieprawidłowe emaile', () => { expect(() => validateEmail('invalid')).toThrow(); expect(() => validateEmail('@example.com')).toThrow(); expect(() => validateEmail('user@')).toThrow(); });
it('powinien naprawić typowe błędy', () => { expect(validateEmail('user@gmial.com')).toBe('user@gmail.com'); expect(validateEmail('user@yahooo.com')).toBe('user@yahoo.com'); });});
// Behavior-Driven Development z AI/** * @cursor Utwórz koszyk zakupowy z testami BDD: * * Funkcja: Koszyk zakupowy * Jako klient * Chcę dodawać produkty do koszyka * Żeby móc kupić wiele produktów * * Scenariusze do testowania: * - Dodawanie produktów * - Usuwanie produktów * - Aktualizacja ilości * - Stosowanie rabatów * - Obliczanie sum */
// AI generuje testy w stylu BDDdescribe('Koszyk zakupowy', () => { describe('gdy dodaję produkty', () => { it('powinien dodać nowy produkt do pustego koszyka', () => { const cart = new ShoppingCart(); cart.addItem({ id: '1', name: 'Książka', price: 10 });
expect(cart.items).toHaveLength(1); expect(cart.total).toBe(10); });
it('powinien zwiększyć ilość dla istniejącego produktu', () => { const cart = new ShoppingCart(); cart.addItem({ id: '1', name: 'Książka', price: 10 }); cart.addItem({ id: '1', name: 'Książka', price: 10 });
expect(cart.items).toHaveLength(1); expect(cart.items[0].quantity).toBe(2); expect(cart.total).toBe(20); }); });
// Więcej scenariuszy...});
// Krok 1: Przeanalizuj istniejące testy/** * @cursor Przeanalizuj te testy i zidentyfikuj: * 1. Jakie mutacje nadal by przeszły * 2. Brakujące asercje * 3. Nietestowane gałęzie * 4. Słabe przypadki testowe * * Następnie wzbogać testy aby wyłapać wszystkie mutacje */
// Oryginalny słaby testit('powinien obliczyć rabat', () => { const result = calculateDiscount(100, 0.1); expect(result).toBeTruthy(); // Słaba asercja});
// AI wzbogaca do silnego testuit('powinien obliczyć rabat poprawnie', () => { const result = calculateDiscount(100, 0.1); expect(result).toBe(90); // Dokładna wartość expect(result).toBeGreaterThan(0); // Dodatni expect(result).toBeLessThan(100); // Mniejszy od oryginalnego
// Testuj warunki graniczne expect(calculateDiscount(100, 0)).toBe(100); expect(calculateDiscount(100, 1)).toBe(0);
// Testuj nieprawidłowe dane wejściowe expect(() => calculateDiscount(-100, 0.1)).toThrow(); expect(() => calculateDiscount(100, 1.5)).toThrow();});
// Generuj testy regresji wizualnej/** * @cursor Utwórz testy regresji wizualnej dla wszystkich komponentów: * 1. Wygeneruj test dla każdego stanu komponentu * 2. Dołącz punkty przerwania responsywne * 3. Testuj motywy ciemny/jasny * 4. Obsłuż stany ładowania/błędów * 5. Przechwyć stany interakcji (hover, focus) */
// AI generuje kompleksowe testy wizualnedescribe('Regresja wizualna przycisku', () => { const sizes = ['small', 'medium', 'large']; const variants = ['primary', 'secondary', 'danger']; const themes = ['light', 'dark']; const states = ['default', 'hover', 'focus', 'disabled'];
sizes.forEach(size => { variants.forEach(variant => { themes.forEach(theme => { states.forEach(state => { it(`powinien pasować ${size} ${variant} ${state} w motywie ${theme}`, async () => { const component = render( <ThemeProvider theme={theme}> <Button size={size} variant={variant} disabled={state === 'disabled'} > Kliknij mnie </Button> </ThemeProvider> );
if (state === 'hover') { await userEvent.hover(component.getByRole('button')); } else if (state === 'focus') { await userEvent.tab(); }
await expect(component).toMatchScreenshot( `button-${size}-${variant}-${state}-${theme}.png` ); }); }); }); }); });});
// Testowanie wizualne pełnych stron/** * @cursor Utwórz testy wizualne na poziomie strony: * 1. Testuj w wielu rozmiarach viewport * 2. Testuj z różnymi stanami danych * 3. Testuj granice błędów * 4. Testuj stany ładowania * 5. Testuj z wyłączonymi animacjami */
describe('Testy wizualne dashboardu', () => { const viewports = [ { width: 375, height: 667, name: 'mobile' }, { width: 768, height: 1024, name: 'tablet' }, { width: 1920, height: 1080, name: 'desktop' } ];
viewports.forEach(({ width, height, name }) => { it(`powinien renderować dashboard na ${name}`, async () => { await page.setViewport({ width, height }); await page.goto('/dashboard'); await page.waitForSelector('[data-loaded="true"]');
const screenshot = await page.screenshot({ fullPage: true, animations: 'disabled' });
expect(screenshot).toMatchImageSnapshot({ customSnapshotIdentifier: `dashboard-${name}`, threshold: 0.01 }); }); });});
// Wygeneruj zestaw testów wydajności/** * @cursor Utwórz testy wydajności dla naszego API: * 1. Testowanie obciążenia (normalny ruch) * 2. Testowanie stresu (szczytowy ruch) * 3. Testowanie skoków (nagły ruch) * 4. Testowanie wytrzymałości (utrzymane obciążenie) * 5. Mierz czasy odpowiedzi, wskaźniki błędów, przepustowość */
// AI generuje testy wydajności k6import http from 'k6/http';import { check, sleep } from 'k6';import { Rate } from 'k6/metrics';
const errorRate = new Rate('errors');
export const options = { stages: [ { duration: '2m', target: 100 }, // Rozbieg { duration: '5m', target: 100 }, // Pozostań na 100 użytkowników { duration: '2m', target: 200 }, // Rozbieg do 200 { duration: '5m', target: 200 }, // Pozostań na 200 { duration: '2m', target: 0 }, // Rozbiegnij w dół ], thresholds: { http_req_duration: ['p(95) < 500'], // 95% poniżej 500ms errors: ['rate < 0.1'], // Wskaźnik błędów poniżej 10% },};
export default function () { // Testuj przepływ logowania użytkownika const loginRes = http.post('https://api.example.com/login', { email: 'test@example.com', password: 'password123' });
check(loginRes, { 'logowanie udane': (r) => r.status === 200, 'czas odpowiedzi OK': (r) => r.timings.duration < 500, });
errorRate.add(loginRes.status !== 200);
sleep(1); // Czas myślenia
// Testuj endpointy API z auth const token = loginRes.json('token'); const headers = { Authorization: `Bearer ${token}` };
// AI generuje testy dla wszystkich endpointów...}
// AI generuje testy oparte na właściwościach/** * @cursor Utwórz testy oparte na właściwościach używając fast-check: * Testuj właściwości matematyczne które zawsze powinny być prawdziwe */
import fc from 'fast-check';
describe('Narzędzia tablicowe', () => { it('powinien utrzymać długość przy tasowaniu', () => { fc.assert( fc.property(fc.array(fc.integer()), (arr) => { const shuffled = shuffle([...arr]); return shuffled.length === arr.length; }) ); });
it('powinien zawierać te same elementy po tasowaniu', () => { fc.assert( fc.property(fc.array(fc.integer()), (arr) => { const shuffled = shuffle([...arr]); const sortedOriginal = [...arr].sort(); const sortedShuffled = [...shuffled].sort(); return JSON.stringify(sortedOriginal) === JSON.stringify(sortedShuffled); }) ); });});
// Testy kontraktów opartych na konsumentach/** * @cursor Wygeneruj testy kontraktów między: * - Frontend (konsument) * - Backend API (dostawca) * * Dołącz wszystkie endpointy i formaty danych */
// AI generuje testy Pactdescribe('Kontrakt API użytkownika', () => { const provider = new Pact({ consumer: 'Frontend', provider: 'UserAPI', });
describe('pobierz użytkownika', () => { it('powinien zwrócić szczegóły użytkownika', async () => { // Oczekiwanie konsumenta await provider.addInteraction({ state: 'użytkownik istnieje', uponReceiving: 'żądanie użytkownika', withRequest: { method: 'GET', path: '/users/123', headers: { Accept: 'application/json' }, }, willRespondWith: { status: 200, headers: { 'Content-Type': 'application/json' }, body: { id: '123', name: like('Jan Kowalski'), email: term({ matcher: '.+@.+\\..+', generate: 'jan@example.com' }), createdAt: iso8601DateTime(), }, }, });
// Testuj kod konsumenta const user = await fetchUser('123'); expect(user.id).toBe('123'); expect(user.name).toBeTruthy(); expect(user.email).toMatch(/@/); }); });});
// Auto-aktualizuj testy gdy kod się zmienia/** * @cursor Funkcja processOrder zmieniła się. * Zaktualizuj wszystkie powiązane testy aby pasowały do nowej sygnatury * i zachowania zachowując pokrycie. * * Stare: processOrder(orderId, userId) * Nowe: processOrder(order, options) */
// AI automatycznie aktualizuje wszystkie dotknięte testy
Metryka | Testowanie manualne | Wspomagane przez AI | Poprawa |
---|---|---|---|
Czas tworzenia testów | 4 godziny | 20 minut | 92% szybciej |
Pokrycie kodu | 45% | 85% | 89% wzrost |
Znalezione przypadki brzegowe | 5-10 | 30-50 | 5x więcej |
Czas utrzymania | 2 godz/tydzień | 15 min/tydzień | 87% mniej |
Wskaźnik ucieczki błędów | 12% | 3% | 75% redukcja |
Opanuj wzorce testowania aby:
Kontynuuj z:
Pamiętaj: Najlepszy zestaw testów to ten który wyłapuje błędy, działa szybko i sam się utrzymuje. Pozwól AI obsłużyć powtarzalne części podczas gdy ty skupiasz się na strategii testów i jakości.