Synthèse automatique
Définit les normes de test des services Meridian en Go : suppression des time.Sleep au profit du package await, tests d'intégration PostgreSQL via testcontainers et tests table-driven documentés.
Points forts
- Remplace time.Sleep par des assertions asynchrones avec timeout et intervalle de polling configurables, ce qui élimine une cause fréquente de tests instables
- Impose une isolation par conteneur via testdb/testhelpers avec un defer Cleanup systématique
- Exige un champ rationale par cas de test, ce qui documente l'intention et facilite la revue
- Rappelle la couverture des chemins d'erreur (defensive testing, ADR-0008) en plus des happy paths
Limites
- Fortement lié à l'écosystème Meridian (shared/platform/await, testdb, ADR-0008) et peu transposable tel quel ailleurs
- Suppose Go et testify ; aucun exemple pour d'autres langages ou frameworks de test
- Le package await est présenté sans code source ni garanties sur sa stratégie de polling en cas d'échec
À utiliser lorsqu'on écrit ou corrige des tests Go dans un service Meridian, notamment en cas de flakiness, de tests asynchrones ou de tests d'intégration base de données.
À éviter sur un projet non-Meridian ou non-Go, car les packages et conventions référencés n'y existent pas.
Analyse de sécurité
SûrThe skill contains only static testing guidance and code examples. It declares no tools and does not instruct any destructive, exfiltrating, or obfuscated actions. The content is purely informational for developers.
Aucun point d'attention détecté
Comment cette analyse est faiteExemples
My TestOrderCompletion in the payments service uses time.Sleep(2 * time.Second) and fails intermittently in CI. Rewrite it using the Meridian await package with a proper timeout.Write a repository integration test for the ledger service that spins up an isolated Postgres container with testhelpers.SetupTestContainer and verifies Create and FindByID.Convert TestDeposit into a table-driven test following Meridian standards, including a rationale field and both happy-path and unhappy-path cases.name: skill-testing-standards description: Testing standards and best practices for Meridian services triggers:
- Writing tests
- Test flakiness or failures
- Using time.Sleep in tests
- Async or polling tests
- Integration tests
- Database tests
- Test coverage
instructions: | Use await package instead of time.Sleep. Use testcontainers for database tests. Apply defensive testing (ADR-0008): test happy paths AND unhappy paths. Table-driven tests with rationale field. Use testify assert/require.
Testing Standards
This document defines testing standards for Meridian services.
Core Principles
- No
time.Sleep- Use theawaitpackage for async assertions - Defensive testing - Test happy paths AND unhappy paths (see ADR-0008)
- Table-driven tests - Use Go table-driven patterns with rationale
- Isolation - Tests must not depend on each other
- Fast feedback - Unit tests should complete in milliseconds
Async Testing: Use await Not time.Sleep
NEVER use time.Sleep in tests. It creates flaky tests - too short causes failures, too long wastes CI time.
Use shared/platform/await instead. It polls until conditions are met or timeout.
import "github.com/meridianhub/meridian/shared/platform/await"
// BAD - arbitrary sleep, flaky and slow
time.Sleep(2 * time.Second)
assert.Equal(t, "COMPLETED", order.Status)
// GOOD - polls until condition met or timeout
err := await.Until(func() bool {
return order.Status == "COMPLETED"
})
require.NoError(t, err)
// With custom timeout and poll interval
err := await.New().
AtMost(5 * time.Second).
PollInterval(50 * time.Millisecond).
Until(func() bool {
return repo.FindByID(ctx, id) != nil
})
// Wait for an operation to succeed (no error)
err := await.UntilNoError(func() error {
return client.HealthCheck()
})
// With context cancellation
err := await.New().
WithContext(ctx).
AtMost(10 * time.Second).
Until(condition)
Defaults: 10s timeout, 100ms poll interval.
For advanced matchers and more expressive assertions, consider gomega.Eventually().
Database Integration Tests: Use Testcontainers
Use shared/platform/testdb/ for PostgreSQL integration tests. Each test gets an isolated container.
import "github.com/meridianhub/meridian/internal/<service>/repository/testhelpers"
func TestRepository(t *testing.T) {
tc := testhelpers.SetupTestContainer(t)
defer tc.Cleanup(t) // CRITICAL - always defer cleanup
// Use tc.Repo for repository operations
err := tc.Repo.Create(ctx, entity)
require.NoError(t, err)
// Or use tc.Pool for direct SQL
var count int
err = tc.Pool.QueryRow(ctx, "SELECT COUNT(*) FROM table").Scan(&count)
require.NoError(t, err)
}
See Testcontainers Usage Guide for detailed patterns.
Table-Driven Tests with Rationale
Every test case must include a rationale field explaining WHY it matters:
func TestDeposit(t *testing.T) {
tests := []struct {
name string
amount int64
wantErr bool
rationale string // WHY this test case matters
}{
// Happy path
{
name: "valid deposit",
amount: 100,
wantErr: false,
rationale: "Standard valid deposit should succeed",
},
// Edge cases
{
name: "minimum valid amount",
amount: 1,
wantErr: false,
rationale: "Even 1 cent is a valid deposit",
},
// Unhappy paths
{
name: "zero amount rejected",
amount: 0,
wantErr: true,
rationale: "Zero deposits are meaningless operations",
},
{
name: "negative amount rejected",
amount: -100,
wantErr: true,
rationale: "Negative deposits don't make sense (use withdraw)",
},
// Defensive: values that shouldn't happen but might
{
name: "overflow detection",
amount: math.MaxInt64,
wantErr: true,
rationale: "Must detect arithmetic overflow to prevent corruption",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := account.Deposit(tt.amount)
if tt.wantErr {
assert.Error(t, err, tt.rationale)
} else {
assert.NoError(t, err, tt.rationale)
}
})
}
}
Defensive Testing Categories
Apply these categories to all tests (see ADR-0008):
For Numeric Inputs
- Valid values (happy path)
- Zero
- Negative values
- Maximum/minimum boundaries
- Overflow conditions
For String Inputs
- Valid formatted strings
- Empty strings
- Whitespace-only strings
- Invalid formats
- Very long strings
For State Transitions
- Valid transitions
- Invalid transitions (must be rejected)
- Idempotent operations
- Concurrent state changes
For Error Handling
- Every error path has a test
- State is not modified on error
- Resources are cleaned up on error
- Errors wrap correctly (
errors.Is/errors.Aswork)
Test Assertions: Use testify
Use github.com/stretchr/testify for assertions:
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// Use require for setup - fails fast
tc := testhelpers.SetupTestContainer(t)
require.NotNil(t, tc.Pool, "database pool required")
// Use assert for verifications - continues on failure
assert.Equal(t, expected, actual)
assert.NoError(t, err)
assert.ErrorIs(t, err, ErrNotFound)
assert.Contains(t, logs, "expected message")
require vs assert:
require- Stops test immediately on failure (use for setup/preconditions)assert- Records failure but continues (use for verifications)
Test Naming
Use descriptive names that explain the scenario:
// GOOD - describes scenario and expected outcome
func TestDeposit_ZeroAmount_ReturnsError(t *testing.T)
func TestFindByID_NonExistent_ReturnsNotFoundError(t *testing.T)
func TestTransfer_InsufficientFunds_RollsBackTransaction(t *testing.T)
// BAD - vague names
func TestDeposit1(t *testing.T)
func TestError(t *testing.T)
func TestIt(t *testing.T)
Parallel Tests
Run independent tests in parallel for faster feedback:
func TestConcurrentOperations(t *testing.T) {
t.Parallel() // Mark test as safe for parallel execution
tc := testhelpers.SetupTestContainer(t)
defer tc.Cleanup(t)
// Each parallel test gets its own container
}
When NOT to parallelize:
- Tests sharing global state
- Tests with fixed port bindings
- Tests modifying environment variables
Mocking Guidelines
Minimize mocking. Prefer real implementations where practical:
- Use testcontainers for database tests (real PostgreSQL)
- Use in-memory implementations for simple interfaces
- Mock only external services that can't be containerized
- Never mock the thing you're testing
When mocking is necessary, use github.com/stretchr/testify/mock:
type MockClient struct {
mock.Mock
}
func (m *MockClient) Send(ctx context.Context, msg Message) error {
args := m.Called(ctx, msg)
return args.Error(0)
}
// In test
client := new(MockClient)
client.On("Send", mock.Anything, expectedMsg).Return(nil)
Test Organization
service/
├── domain/
│ ├── account.go
│ └── account_test.go # Unit tests (same package)
├── repository/
│ ├── postgres_repository.go
│ ├── postgres_repository_test.go # Integration tests
│ └── testhelpers/
│ └── container.go # Shared test setup
└── handler/
├── grpc_handler.go
└── grpc_handler_test.go # Handler tests
CI Considerations
- Unit tests run on every commit
- Integration tests (testcontainers) run on PR
- Tests must pass before merge
- Flaky tests must be fixed immediately (not skipped)
Related Documentation
- ADR-0008: Defensive Testing Standards - Testing philosophy
- Testcontainers Usage Guide - Database test setup
- await package - Async polling utility
Du fichier au premier essai
Le téléchargement contient exactement le contenu affiché sur cette fiche. Cette copie peut différer de la dernière version du dépôt source.
Consulter la source et ses fichiers annexesCe téléchargement contient uniquement SKILL.md. Les scripts, références, modèles et dépendances éventuels ne sont pas inclus. Récupérez les fichiers nécessaires depuis la source en conservant leur arborescence avant de poursuivre.
1. Télécharger le fichier
Télécharger SKILL.mdDepuis la racine d’un projet de test, enregistrez le fichier sous .skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md, ou utilisez la commande suivante. Ce dossier sert à examiner la skill avant son installation.
Commande pour macOS/Linux ou WSL : un shell POSIX et curl sont nécessaires. Sous Windows sans WSL, utilisez le bouton de téléchargement et créez le dossier manuellement.
mkdir -p '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/testing-standards-for-meridian-services-mrx3xztb/download' --output '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md.part' && mv '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md.part' '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md'2. Vérifier les prérequis
Lisez SKILL.md avant de l’utiliser. Si le fichier cite des scripts ou services externes, examinez-les et préparez les accès nécessaires dans votre environnement de test.
Aucune section de prérequis reconnue dans ce fichier. Cela ne signifie pas qu’il est autonome : les bibliothèques, outils et accès peuvent être cités ailleurs dans le contenu ou dans le dépôt source.
Les plateformes de la fiche sont des indications du catalogue. Les chemins ci-dessous suivent la documentation des outils ; ils ne prouvent pas que cette skill y a été exécutée. Aucune version minimale de ces outils n’est attestée pour cette fiche.
3. Charger la skill
Après vérification, copiez le dossier complet dans le projet avec l’une des commandes ci-dessous, puis ouvrez une nouvelle session de l’outil. La commande s’arrête si un dossier du même nom existe déjà : comparez les fichiers avant de le remplacer.
Claude Code
test -f '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md' && test -s '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/skill-testing-standards' && cp -R '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb' '.claude/skills/skill-testing-standards'Cursor
test -f '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md' && test -s '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md' && mkdir -p '.cursor/skills' && test ! -e '.cursor/skills/skill-testing-standards' && cp -R '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb' '.cursor/skills/skill-testing-standards'Codex
test -f '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md' && test -s '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md' && mkdir -p '.agents/skills' && test ! -e '.agents/skills/skill-testing-standards' && cp -R '.skill-downloads/testing-standards-for-meridian-services-mrx3xztb' '.agents/skills/skill-testing-standards'OpenSkills
OpenSkills doit déjà être installé. La procédure locale install/read est contrôlée avec OpenSkills 1.5.0, qui exige Node.js ≥ 20.6.0. Aucun slug du catalogue n’est résolu automatiquement.
Installation officielle d’OpenSkillsopenskills install './.skill-downloads/testing-standards-for-meridian-services-mrx3xztb'openskills read 'testing-standards-for-meridian-services-mrx3xztb'La lecture doit afficher le contenu du fichier installé et son dossier de base. Elle ne lance ni la skill ni ses dépendances.
Pour un agent qui lit AGENTS.md, synchronisez ensuite l’index. Cette commande modifie AGENTS.md : relisez le diff avant de l’utiliser.
openskills syncMode manuel ou autre outil : joignez SKILL.md à une conversation, ou ouvrez-le dans un agent capable de lire les fichiers. Ajoutez les ressources annexes nécessaires. Il n’existe pas de dossier universel reconnu par tous les outils.
4. Faire un premier essai
Utilisez une entrée courte et fictive : un endpoint d’API, un petit document ou un brief d’interface. Dans une nouvelle conversation, joignez le fichier ou donnez son chemin à l’agent, puis adaptez cette demande :
Lis .skill-downloads/testing-standards-for-meridian-services-mrx3xztb/SKILL.md et applique ses instructions à cet exemple : [décrire une entrée de test]. Indique les fichiers, dépendances ou accès qui manquent. Produis le résultat demandé par la skill sans inventer de données ni exécuter de script non examiné.Résultat attendu : une sortie correspondant aux instructions de la skill, ou une liste précise des prérequis manquants. Une simple confirmation de lecture ne valide pas le premier usage. Si une ressource externe est indisponible, ce parcours reste à tester.
Comparaison de performances ClickHouse
Testing
Évaluez les résultats de tests de performance ClickHouse, analysez les régressions de PR, comparez avec l'historique et vérifiez la fiabilité des mesures.
Analyse des rapports de performance CI
Testing
Analyse les rapports de comparaison de performance CI pour une PR ClickHouse. Recoupe l'historique master pour distinguer les vraies régressions des tests instables.
Méthode Santa
Testing
Vérification adversarial multi-agents avec deux réviseurs indépendants. La sortie est vérifiée deux fois et corrigée itérativement jusqu'à ce que les deux acceptent avant publication.