Agent de révision principal

Analyste de tests

Garantit que vos tests vous protègent réellement

Des tests qui passent ne signifient pas que votre code fonctionne. L'analyste de tests trouve les lacunes — cas limites manquants, tests instables et problèmes d'isolation qui laissent passer les bugs.

Ce que détecte l'analyste de tests

Les lacunes dans votre suite de tests qui laissent échapper les bugs

Couverture des cas limites manquante

Le parcours idéal est testé, mais qu'en est-il des valeurs nulles, des tableaux vides et des conditions limites ?

Entrées nullesCollections videsValeurs limitesChemins d'erreur

Tests instables

Des tests qui passent parfois et échouent d'autres fois — les tueurs silencieux de la confiance CI/CD

Dépendances temporellesDépendances d'ordreÉtat partagéAppels réseau

Mauvaise isolation des tests

Des tests qui dépendent les uns des autres ou partagent un état mutable — des cauchemars de débogage

Fixtures partagésPollution de base de donnéesÉtat globalBugs d'ordre de test

Tous les types de tests couverts

Des tests unitaires aux tests E2E, l'analyste de tests les examine tous

Tests unitaires

Tests au niveau des fonctions et classes

Tests d'intégration

Tests d'interaction entre composants

Tests E2E

Tests de parcours utilisateur de bout en bout

Tests API

Tests d'endpoints et de contrats

Tests de snapshot

Détection de régressions UI

Tests de performance

Tests de charge et de benchmark

Amélioration de la qualité des tests

Exemples réels d'améliorations de tests

Cas limite manquant

Test faible
describe('calculateDiscount', () => {
  it('applies 10% for orders over $100', () => {
    expect(calculateDiscount(150)).toBe(15)
  })

  it('applies 5% for orders over $50', () => {
    expect(calculateDiscount(75)).toBe(3.75)
  })

  // What about $0? Negative? Exactly $50? $100?
})

Tests de limites manquants : $0, $50, $100, valeurs négatives

Test robuste
describe('calculateDiscount', () => {
  it('applies 10% for orders over $100', () => {
    expect(calculateDiscount(150)).toBe(15)
  })

  it('applies 5% for orders over $50', () => {
    expect(calculateDiscount(75)).toBe(3.75)
  })

  it('returns 0 for orders at boundary', () => {
    expect(calculateDiscount(50)).toBe(0)
    expect(calculateDiscount(100)).toBe(5) // 5% tier
  })

  it('handles zero and negative gracefully', () => {
    expect(calculateDiscount(0)).toBe(0)
    expect(calculateDiscount(-10)).toBe(0)
  })
})

Ajouter des cas limites pour les frontières et entrées invalides

Détection de test instable

Test faible
it('shows notification after save', async () => {
  await user.click(saveButton)

  // Flaky! Depends on timing
  await waitFor(() => {
    expect(screen.getByText('Saved!')).toBeVisible()
  })

  // Even worse: arbitrary timeout
  await new Promise(r => setTimeout(r, 100))
  expect(notificationCount).toBe(1)
})

Timeouts arbitraires et hypothèses temporelles

Test robuste
it('shows notification after save', async () => {
  await user.click(saveButton)

  // Wait for specific state change
  await waitFor(() => {
    expect(screen.getByRole('alert')).toHaveTextContent('Saved!')
  })

  // Assert on observable behavior, not timing
  expect(
    await screen.findByRole('alert', { name: /saved/i })
  ).toBeVisible()
})

Attendre des changements d'état observables, pas le temps

Problème d'isolation de test

Test faible
let testUser: User

beforeAll(async () => {
  // Shared across ALL tests — mutations leak!
  testUser = await createUser({ name: 'Test' })
})

it('updates user name', async () => {
  await updateUser(testUser.id, { name: 'Updated' })
  // Now testUser.name is 'Updated' for all following tests
})

it('checks original name', () => {
  // FAILS! Previous test mutated shared state
  expect(testUser.name).toBe('Test')
})

État partagé dans beforeAll qui fuit entre les tests

Test robuste
describe('user updates', () => {
  let testUser: User

  beforeEach(async () => {
    // Fresh user for EACH test
    testUser = await createUser({ name: 'Test' })
  })

  afterEach(async () => {
    await deleteUser(testUser.id)
  })

  it('updates user name', async () => {
    await updateUser(testUser.id, { name: 'Updated' })
    expect(testUser.name).toBe('Updated')
  })

  it('checks original name', () => {
    // Works! Fresh testUser with original name
    expect(testUser.name).toBe('Test')
  })
})

Utiliser beforeEach pour l'isolation des tests

Analyse des tests

Comment fonctionne l'analyste de tests

L'analyste de tests ne se contente pas de compter les tests — il analyse ce qu'ils testent réellement. Il trouve les lacunes entre ce que vos tests couvrent et ce dont votre code a besoin.

Analyse des chemins

Cartographie les chemins de code pour trouver les branches non testées

Détection d'instabilité

Identifie les dépendances temporelles et d'ordre

Suggestions de cas limites

Recommande des cas de test spécifiques à ajouter

Pipeline d'analyse

1

Analyser la couverture des tests

Cartographie les chemins de code testés et ceux qui ne le sont pas

2

Identifier les points faibles

Trouve les cas limites et conditions d'erreur sans tests

3

Détecter les anti-patterns

Repère les patterns instables et problèmes d'isolation

4

Suggérer des améliorations

Recommande des cas de test spécifiques à ajouter

Pourquoi la qualité des tests compte

De mauvais tests sont pires que pas de tests — ils donnent une fausse confiance

Détecter les vrais bugs

Les tests qui couvrent les cas limites détectent les bugs avant les utilisateurs

CI/CD fiable

Fini le "réessayer jusqu'au vert" — les tests passent ou échouent pour de vraies raisons

Refactorer en toute sécurité

De bons tests vous permettent de modifier le code en toute confiance

Une couverture à 100% ne signifie rien si les tests ne détectent pas les bugs.
L'analyste de tests garantit que vos tests fonctionnent réellement.

Des tests qui vous
protègent réellement

Laissez l'analyste de tests trouver les lacunes dans votre suite de tests. Gratuit pendant 14 jours, sans carte de crédit.

Détection des cas limites
Prévention des tests instables
Analyse d'isolation