Przejdź do głównej zawartości

Test-driven development - Cursor

Budujesz silnik obliczeń finansowych dla platformy inwestycyjnej. Wymagania obejmują obliczenia odsetek składanych, algorytmy rebalansowania portfela, strategie optymalizacji podatkowej i ocenę ryzyka. Obliczenia muszą być w 100% dokładne, obsługiwać przypadki brzegowe i być dokładnie udokumentowane. Twój zespół wymaga podejścia TDD z >95% pokryciem testami.

Po ukończeniu tej lekcji opanujesz:

  • Pisanie testów przed implementacją z AI
  • Efektywne tworzenie kompleksowych zestawów testów
  • Używanie AI do odkrywania przypadków brzegowych
  • Testowanie oparte na właściwościach z asystencją AI
  • Dokumentację i utrzymanie testów
  • Testowanie wydajności i integracji
  • Zrozumienie koncepcji testowania
  • Podstawowa znajomość Jest/Vitest
  • Ukończone poprzednie lekcje
  • Znajomość kalkulatora lub domeny finansów pomocna
  • Opcjonalnie: Playwright MCP do testowania przeglądarki (zobacz konfigurację)

Zbuduj silnik obliczeń używając czystego TDD:

  • Napisz wszystkie testy przed implementacją
  • Osiągnij 100% pokrycie kodu
  • Obsłuż wszystkie przypadki brzegowe
  • Stwórz testy oparte na właściwościach
  • Dokumentuj scenariusze testowe
  • Zapewnij dokładność obliczeń
  1. Zdefiniuj strategię testową

Zacznij od analizy wymagań:

"Muszę zbudować silnik obliczeń finansowych z tymi funkcjami:
1. Kalkulator odsetek składanych
2. Rebalansowanie portfela
3. Tax loss harvesting
4. Ocena ryzyka (wskaźnik Sharpe'a, itd.)
Pomóż mi stworzyć kompleksowy plan testów zgodnie z zasadami TDD.
Jakie kategorie testów i scenariusze powinienem rozważyć?"
  1. Stwórz strukturę testów
"Zaprojektuj strukturę plików testowych dla:
- Testów jednostkowych każdego obliczenia
- Testów integracji dla workflow
- Testów opartych na właściwościach dla właściwości matematycznych
- Testów wydajności dla dużych portfeli
- Testów snapshot dla raportów
Stwórz strukturę katalogów i szablony testów"
  1. Wygeneruj narzędzia testowe

Przełącz się na tryb Agent:

"Stwórz narzędzia i helpery testowe:
- Fabryki danych testowych dla portfeli
- Helpery asercji dla wartości finansowych
- Generatory mock danych
- Custom matchery dla precyzji
- Fixtures testowe dla typowych scenariuszy"

Przykład narzędzi testowych:

test-utils/financial.ts
export const expectFinanciallyEqual = (
actual: number,
expected: number,
precision: number = 2
) => {
const multiplier = Math.pow(10, precision);
expect(Math.round(actual * multiplier)).toBe(
Math.round(expected * multiplier)
);
};
export const createPortfolio = (overrides?: Partial<Portfolio>): Portfolio => ({
id: faker.string.uuid(),
name: faker.company.name() + ' Portfolio',
holdings: [
{
symbol: 'AAPL',
shares: faker.number.int({ min: 10, max: 1000 }),
costBasis: faker.number.float({ min: 100, max: 200 }),
},
{
symbol: 'GOOGL',
shares: faker.number.int({ min: 5, max: 500 }),
costBasis: faker.number.float({ min: 1000, max: 3000 }),
},
],
cash: faker.number.float({ min: 1000, max: 100000 }),
...overrides,
});
export const createMarketData = (): MarketData => ({
AAPL: { price: 150.00, change: 0.02 },
GOOGL: { price: 2800.00, change: -0.01 },
// ... więcej symboli
});
  1. Test kalkulatora odsetek składanych
"Napisz kompleksowe testy dla obliczenia odsetek składanych:
- Podstawowe obliczenie z rocznym składaniem
- Różne częstotliwości składania (miesięczne, dzienne, ciągłe)
- Przypadki brzegowe (ujemne stopy, zero kapitału, wartości ekstremalne)
- Zachowanie precyzji i zaokrąglania
- Obsługa nieprawidłowych wejść
Dołącz wzór matematyczny w komentarzach"

Przykład zestawu testów:

__tests__/calculators/compound-interest.test.ts
describe('CompoundInterestCalculator', () => {
describe('calculate()', () => {
// Wzór: A = P(1 + r/n)^(nt)
// A = kwota końcowa, P = kapitał, r = stopa, n = składania na rok, t = czas
it('powinno obliczyć proste roczne odsetki składane', () => {
const result = calculateCompoundInterest({
principal: 1000,
rate: 0.05,
time: 10,
compoundingFrequency: 1,
});
// 1000 * (1 + 0.05/1)^(1*10) = 1628.89
expectFinanciallyEqual(result.finalAmount, 1628.89);
expectFinanciallyEqual(result.totalInterest, 628.89);
});
it('powinno obsłużyć składanie miesięczne', () => {
const result = calculateCompoundInterest({
principal: 1000,
rate: 0.05,
time: 10,
compoundingFrequency: 12,
});
// 1000 * (1 + 0.05/12)^(12*10) = 1647.01
expectFinanciallyEqual(result.finalAmount, 1647.01);
});
it('powinno obsłużyć składanie ciągłe', () => {
const result = calculateCompoundInterest({
principal: 1000,
rate: 0.05,
time: 10,
compoundingFrequency: 'continuous',
});
// P * e^(rt) = 1000 * e^(0.05*10) = 1648.72
expectFinanciallyEqual(result.finalAmount, 1648.72);
});
describe('przypadki brzegowe', () => {
it('powinno obsłużyć zero kapitału', () => {
const result = calculateCompoundInterest({
principal: 0,
rate: 0.05,
time: 10,
});
expect(result.finalAmount).toBe(0);
});
it('powinno obsłużyć ujemne stopy procentowe', () => {
const result = calculateCompoundInterest({
principal: 1000,
rate: -0.02,
time: 5,
});
expectFinanciallyEqual(result.finalAmount, 904.84);
});
it('powinno obsłużyć bardzo duże liczby bez przepełnienia', () => {
const result = calculateCompoundInterest({
principal: 1e10,
rate: 0.15,
time: 50,
});
expect(result.finalAmount).toBeGreaterThan(0);
expect(result.finalAmount).toBeLessThan(Infinity);
});
});
describe('walidacja', () => {
it('powinno rzucić dla nieprawidłowego kapitału', () => {
expect(() =>
calculateCompoundInterest({
principal: NaN,
rate: 0.05,
time: 10,
})
).toThrow('Kapitał musi być prawidłową liczbą');
});
it('powinno rzucić dla nieprawidłowego okresu czasu', () => {
expect(() =>
calculateCompoundInterest({
principal: 1000,
rate: 0.05,
time: -5,
})
).toThrow('Okres czasu musi być dodatni');
});
});
});
});
  1. Test rebalansowania portfela
@test-utils/financial.ts
"Stwórz testy dla algorytmu rebalansowania portfela:
- Rebalansowanie alokacji docelowej
- Rebalansowanie oparte na progach
- Rebalansowanie uwzględniające podatki
- Minimalizacja kosztów transakcji
- Przypadki brzegowe (niepłynne aktywa, ograniczenia)
Testuj zarówno algorytm jak i jego optymalizacje"
  1. Test obliczeń ryzyka
"Napisz testy dla metryk ryzyka:
- Obliczenie wskaźnika Sharpe'a
- Odchylenie standardowe zwrotów
- Maksymalny drawdown
- Value at Risk (VaR)
- Obliczenie beta
Dołącz testy dla różnych okresów czasu i jakości danych"
  1. Zdefiniuj właściwości
"Stwórz testy oparte na właściwościach dla obliczeń finansowych:
- Właściwości matematyczne (łączność, rozdzielność)
- Niezmienniki (wartość portfela = suma holdingów + gotówka)
- Granice (zwroty między -100% a +∞)
- Monotoniczność (więcej czasu = więcej odsetek składanych)
Użyj biblioteki fast-check"

Przykład testów właściwości:

__tests__/properties/calculations.property.test.ts
import fc from 'fast-check';
describe('Właściwości obliczeń finansowych', () => {
describe('Właściwości odsetek składanych', () => {
it('powinno zawsze rosnąć z dodatnią stopą i czasem', () => {
fc.assert(
fc.property(
fc.float({ min: 100, max: 1000000 }), // kapitał
fc.float({ min: 0.001, max: 0.20 }), // stopa
fc.integer({ min: 1, max: 50 }), // lata
(principal, rate, time) => {
const result = calculateCompoundInterest({
principal,
rate,
time,
});
expect(result.finalAmount).toBeGreaterThan(principal);
expect(result.totalInterest).toBeGreaterThan(0);
}
)
);
});
it('powinno być monotoniczne względem czasu', () => {
fc.assert(
fc.property(
fc.float({ min: 100, max: 1000000 }),
fc.float({ min: 0.001, max: 0.20 }),
fc.integer({ min: 1, max: 30 }),
fc.integer({ min: 1, max: 20 }),
(principal, rate, time1, extraTime) => {
const time2 = time1 + extraTime;
const result1 = calculateCompoundInterest({
principal, rate, time: time1
});
const result2 = calculateCompoundInterest({
principal, rate, time: time2
});
expect(result2.finalAmount).toBeGreaterThan(result1.finalAmount);
}
)
);
});
});
describe('Właściwości portfela', () => {
it('powinno zachować całkowitą wartość przez rebalansowanie', () => {
fc.assert(
fc.property(
fc.array(
fc.record({
symbol: fc.string({ minLength: 1, maxLength: 5 }),
shares: fc.integer({ min: 1, max: 1000 }),
price: fc.float({ min: 1, max: 5000 }),
}),
{ minLength: 2, maxLength: 10 }
),
fc.float({ min: 0, max: 100000 }),
(holdings, cash) => {
const portfolio = { holdings, cash };
const totalBefore = calculatePortfolioValue(portfolio);
const rebalanced = rebalancePortfolio(portfolio, {
STOCKS: 0.6,
BONDS: 0.3,
CASH: 0.1,
});
const totalAfter = calculatePortfolioValue(rebalanced);
// Uwzględnij koszty transakcji
expect(totalAfter).toBeGreaterThanOrEqual(totalBefore * 0.99);
expect(totalAfter).toBeLessThanOrEqual(totalBefore);
}
)
);
});
});
});
  1. Test niezmienników
"Wygeneruj testy dla niezmienników systemu:
- Zachowanie wartości w transakcjach
- Brak ujemnych holdingów po rebalansowaniu
- Metryki ryzyka w prawidłowych zakresach
- Obliczenia podatkowe nigdy ujemne
Stwórz testy właściwości dla każdego niezmiennika"
  1. Fuzz testing
"Stwórz testy fuzz dla:
- Granic walidacji wejścia
- Limitów precyzji obliczeń
- Operacji równoczesnych
- Spójności stanu
Generuj losowe ale prawidłowe dane testowe"
  1. Skonfiguruj Playwright MCP
~/.cursor/mcp.json
{
"mcpServers": {
"playwright": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-puppeteer"]
}
}
}
  1. Testowanie E2E z MCP
"Używając Playwright MCP, przetestuj dashboard inwestycyjny:
1. Przejdź do localhost:3000
2. Zaloguj się danymi testowymi
3. Weryfikuj że wartość portfela wyświetla się poprawnie
4. Kliknij przycisk 'Rebalance'
5. Zrób screenshot modalu potwierdzenia
6. Weryfikuj że pojawia się komunikat sukcesu"
// MCP obsługuje automatyzację przeglądarki
"Używając Playwright MCP:
- Wypełnij formularz odsetek składanych z kapitał=10000, stopa=5%, czas=10
- Kliknij przycisk Calculate
- Weryfikuj że wynik pokazuje $16,288.95
- Zrób screenshot dla testu regresji wizualnej"
  1. Testowanie regresji wizualnej
"Używając Playwright MCP:
- Przejdź do strony biblioteki komponentów
- Zrób screenshot każdego komponentu kalkulatora
- Porównaj z obrazami baseline
- Raportuj wszelkie różnice wizualne"
  1. Testowanie dostępności
"Używając Playwright MCP, uruchom audyt dostępności:
- Przejdź do każdej strony
- Uruchom skan dostępności axe
- Sprawdź współczynniki kontrastu kolorów
- Weryfikuj nawigację klawiaturą
- Testuj ogłoszenia screen readera
- Wygeneruj raport dostępności"
  1. Testowanie wydajności przez przeglądarkę
"Używając Playwright MCP, zmierz wydajność:
- Przejdź do dashboard z śledzeniem wydajności
- Zmierz time to interactive (TTI)
- Sprawdź largest contentful paint (LCP)
- Monitoruj cumulative layout shift (CLS)
- Wygeneruj raport wydajności z metrykami"
// Symulacja real user monitoring
"Symuluj podróż użytkownika z Playwright MCP:
1. Wyląduj na homepage (zmierz czas ładowania)
2. Przejdź do kalkulatora (zmierz przejście)
3. Wykonaj 10 obliczeń (zmierz responsywność)
4. Wygeneruj raport (zmierz czas renderowania)
Zarejestruj wszystkie metryki wydajności"

Testowanie równoległe:

"Używając Playwright MCP, uruchom testy równolegle:
- Test 1: Przepływ rebalansowania portfela
- Test 2: Workflow obliczeń podatkowych
- Test 3: Generowanie raportów
- Test 4: Aktualizacja ustawień użytkownika
Uruchom wszystkie jednocześnie i raportuj wyniki"

Mockowanie API:

"Używając Playwright MCP z przechwytywaniem sieci:
- Mockuj odpowiedzi API danych rynkowych
- Testuj scenariusze błędów (500, timeout)
- Weryfikuj UI obsługi błędów
- Testuj stany ładowania
- Waliduj mechanizmy retry"

Testowanie zarządzania stanem:

"Testuj złożony stan z Playwright MCP:
- Otwórz aplikację w dwóch kartach przeglądarki
- Aktualizuj portfel w karcie 1
- Weryfikuj że karta 2 odzwierciedla zmiany
- Testuj aktualizacje optymistyczne
- Weryfikuj rozwiązywanie konfliktów"
  1. Scenariusze testów integracji
"Stwórz testy integracji dla kompletnych workflow:
- Wdrażanie nowego inwestora z początkowym portfelem
- Miesięczne rebalansowanie z aktualizacjami rynku
- Tax loss harvesting na koniec roku
- Generowanie raportów wydajności
Testuj pełny przepływ z realistycznymi danymi"

Przykład testu integracji:

__tests__/integration/investor-workflow.test.ts
describe('Integracja workflow inwestora', () => {
let investor: Investor;
let marketData: MarketDataService;
beforeEach(() => {
investor = createInvestor({
initialDeposit: 100000,
riskTolerance: 'moderate',
taxBracket: 0.32,
});
marketData = new MockMarketDataService();
});
it('powinno obsłużyć kompletny miesięczny workflow rebalansowania', async () => {
// Początkowe tworzenie portfela
const portfolio = await createPortfolio(investor, {
strategy: 'aggressive-growth',
constraints: {
minCash: 5000,
maxSinglePosition: 0.25,
},
});
expect(portfolio.holdings).toHaveLength(15);
expectPortfolioValid(portfolio);
// Symuluj miesiąc ruchów rynkowych
await marketData.simulateMonth();
// Sprawdź potrzebę rebalansowania
const analysis = analyzePortfolio(portfolio, marketData);
expect(analysis.rebalancingNeeded).toBe(true);
expect(analysis.drift).toBeGreaterThan(0.05);
// Wykonaj rebalansowanie
const trades = await rebalancePortfolio(portfolio, {
marketData,
taxAware: true,
minTradeSize: 100,
});
expect(trades).toHaveLength(8);
expect(trades.every(t => t.taxImpact !== undefined)).toBe(true);
// Zastosuj transakcje i weryfikuj
const newPortfolio = applyTrades(portfolio, trades);
expectPortfolioValid(newPortfolio);
expect(calculateDrift(newPortfolio)).toBeLessThan(0.01);
});
});
  1. Testy wydajności
"Stwórz benchmarki wydajności:
- Oblicz 10,000 portfeli w poniżej 1 sekundy
- Rebalansuj portfel 1,000 aktywów w poniżej 100ms
- Wygeneruj raport podatkowy za 1 rok w poniżej 500ms
- Obliczenia ryzyka na 5 lat danych w poniżej 50ms
Dołącz testy użycia pamięci"
  1. Testy obciążenia
"Zaprojektuj testy obciążenia dla:
- Równoczesnych obliczeń portfela
- Aktualizacji danych rynkowych podczas rebalansowania
- Wielu żądań optymalizacji podatkowej
- Generowania raportów pod obciążeniem
Zapewnij thread safety i dokładność"
  1. Wygeneruj dokumentację testów
"Stwórz kompleksową dokumentację testów:
- Raport pokrycia testami z wyjaśnieniami
- Katalog przypadków brzegowych z przykładami
- Baseline benchmarków wydajności
- Przewodnik generowania danych testowych
- Przewodnik rozwiązywania problemów z błędami"
  1. Stwórz wizualne raporty testów
"Zbuduj wizualne raportowanie testów:
- Mapy cieplne pokrycia
- Wykresy trendów wydajności
- Wykrywanie flaky testów
- Timeline wykonania testów
- Analiza wzorców błędów"
  1. Implementuj helpery testowe
"Stwórz zaawansowane helpery testowe:
- Testowanie snapshot dla obliczeń
- Testowanie golden file dla raportów
- Konfiguracja mutation testing
- Contract testing dla API
- Automatyzacja testów regresji"

Używaj AI i MCP do znajdowania przypadków brzegowych:

// Metoda 1: Używanie Playwright MCP do testowania UI
"Używając Playwright MCP, eksploruj UI kalkulatora i znajdź:
- Przypadki brzegowe walidacji wejścia
- Stany UI nie pokryte testami jednostkowymi
- Problemy dostępności
- Wąskie gardła wydajności w renderowaniu"
// Metoda 2: Używanie bazy danych MCP do testowania danych
"Używając PostgreSQL MCP, przeanalizuj schemat i sugeruj:
- Przypadki testowe naruszenia ograniczeń
- Testy izolacji transakcji potrzebne
- Scenariusze testów wydajności
- Przypadki brzegowe integralności danych"
// Metoda 3: Ręczna analiza implementacji
@implementation/calculator.ts
"Przeanalizuj tę implementację i sugeruj:
1. Brakujące przypadki testowe
2. Potencjalne przypadki brzegowe
3. Warunki błędów nie obsłużone
4. Wąskie gardła wydajności
5. Problemy precyzji"

Podążaj za ścisłym cyklem TDD:

// 1. Napisz failing test
it('powinno obliczyć oszczędności tax-loss harvesting', () => {
const result = calculateTaxLossHarvesting({
losses: 5000,
gains: 8000,
taxRate: 0.32,
});
expect(result.taxSavings).toBe(960); // (5000 - 3000) * 0.32
});
// 2. Zobacz jak się nie udaje
// ❌ calculateTaxLossHarvesting is not defined
// 3. Implementuj minimum do przejścia
function calculateTaxLossHarvesting({ losses, gains, taxRate }) {
const netLoss = Math.min(losses, gains);
return { taxSavings: netLoss * taxRate };
}
// 4. Refaktoryzuj z pewnością

Zapewnij jakość testów:

// Skonfiguruj Stryker dla mutation testing
{
"mutator": {
"name": "typescript",
"excludedMutations": ["StringLiteral"]
},
"testRunner": "jest",
"coverageAnalysis": "perTest",
"thresholds": { "high": 90, "low": 85, "break": 80 }
}

Problem: Testy psują się przy drobnym refaktorowaniu

Rozwiązanie:

// Źle: Testowanie szczegółów implementacji
it('powinno wywołać Math.pow', () => {
const spy = jest.spyOn(Math, 'pow');
calculateCompoundInterest({ ... });
expect(spy).toHaveBeenCalled();
});
// Dobrze: Testowanie zachowania
it('powinno obliczyć poprawny wynik', () => {
const result = calculateCompoundInterest({ ... });
expectFinanciallyEqual(result.finalAmount, 1628.89);
});

Zaawansowane techniki testowania:

  1. Contract testing

    • Kontrakty sterowane przez konsumenta
    • Walidacja schematów
    • Testy kompatybilności API
    • Wykrywanie breaking changes
  2. Chaos testing

    • Losowa iniekcja błędów
    • Symulacja opóźnień sieciowych
    • Testy presji pamięci
    • Testy stresu współbieżności
  3. Testowanie wizualne

    • Testy regresji screenshotów
    • Walidacja renderowania wykresów
    • Weryfikacja formatów raportów
    • Testy wizualne cross-browser
  4. Testowanie napędzane MCP

    • Użyj BrowserStack MCP do testowania urządzeń w chmurze
    • Implementuj SonarQube MCP dla bramek jakości kodu
    • Dodaj Debugg.AI MCP dla generowania testów sterowanego AI
    • Stwórz niestandardowy serwer MCP dla orkiestracji testów

Twoja implementacja TDD jest udana, gdy:

  • ✅ Osiągnięto 100% pokrycie kodu
  • ✅ Wszystkie przypadki brzegowe udokumentowane i przetestowane
  • ✅ Testy działają w poniżej 30 sekund
  • ✅ Zero flaky testów
  • ✅ Wynik mutation >85%
  • ✅ Testy właściwości nie znajdują naruszeń
  • ✅ Benchmarki wydajności spełnione
  • ✅ Dokumentacja kompleksowa

Zespoły używające TDD wspomaganego AI raportują:

  • 90% mniej bugów produkcyjnych
  • 60% szybszą prędkość rozwoju
  • 95% pewności w refaktorowaniu
  • 50% redukcję czasu debugowania

Przed pisaniem implementacji:

  • Wymagania jasno zdefiniowane
  • Struktura testów stworzona
  • Przypadki brzegowe zidentyfikowane
  • Fabryki danych testowych gotowe
  • Asercje zaplanowane
  • Kryteria wydajności ustawione
  • Szablon dokumentacji gotowy
  • Pipeline CI/CD skonfigurowany
  1. Testy najpierw, zawsze: Nigdy nie pisz kodu bez failing testu
  2. AI do odkrywania: Używaj AI do znajdowania przypadków, które przegapisz
  3. Właściwości nad przykładami: Testy właściwości łapią więcej bugów
  4. Testuj kontrakt: Nie implementację
  5. Szybki feedback: Utrzymuj testy szybkie i skupione
  • Planowanie testów: 2 godziny
  • Tworzenie testów jednostkowych: 4 godziny
  • Testy właściwości: 2 godziny
  • Testy integracji: 2 godziny
  • Narzędzia testowe: 2 godziny
  • Łącznie: ~12 godzin (przynosi 40+ godzin oszczędności w debugowaniu)

Opanowałeś TDD z AI. Gotowy na więcej?

Mutation testing

Skonfiguruj zaawansowane mutation testing

Automatyzacja testów

Zbuduj generowanie testów napędzane AI

Testowanie wydajności

Stwórz kompleksowy zestaw wydajności

Kontynuuj do Optymalizacja wydajności →