Initial commit
This commit is contained in:
347
docs/TESTING.md
Normal file
347
docs/TESTING.md
Normal file
@@ -0,0 +1,347 @@
|
||||
# Guide de test - Anagram Generator
|
||||
|
||||
## Structure des tests
|
||||
|
||||
Le projet utilise une architecture de tests modulaire avec les tests séparés du code source. Tous les tests sont situés dans le répertoire `tests/` à la racine du projet.
|
||||
|
||||
```
|
||||
tests/
|
||||
├── analyzer_tests.rs # Tests pour PronounceabilityAnalyzer
|
||||
├── generator_tests.rs # Tests pour AnagramGenerator
|
||||
├── types_tests.rs # Tests pour Anagram et PronouncabilityScore
|
||||
└── integration_tests.rs # Tests d'intégration end-to-end
|
||||
```
|
||||
|
||||
## Types de tests
|
||||
|
||||
### Tests unitaires par module
|
||||
|
||||
#### analyzer_tests.rs
|
||||
Tests du module `analyzer` qui vérifient :
|
||||
- Le scoring des mots prononçables
|
||||
- La classification des caractères (voyelles/consonnes)
|
||||
- La détection des clusters de consonnes communs
|
||||
- Les pénalités pour différents patterns phonétiques
|
||||
- Les bonus pour bonne alternance voyelle-consonne
|
||||
|
||||
**Nombre de tests** : 11
|
||||
|
||||
#### generator_tests.rs
|
||||
Tests du module `generator` qui vérifient :
|
||||
- La génération de valides anagrammes
|
||||
- Le respect du score minimum
|
||||
- L'unicité des anagrammes générés
|
||||
- Le tri par score
|
||||
- L'exclusion du mot original
|
||||
- La normalisation de l'entrée
|
||||
- Le pattern builder de configuration
|
||||
|
||||
**Nombre de tests** : 9
|
||||
|
||||
#### types_tests.rs
|
||||
Tests des types de domaine qui vérifient :
|
||||
- La création et manipulation de `PronouncabilityScore`
|
||||
- Les opérations saturantes (add/sub)
|
||||
- Le clamping des valeurs (0-100)
|
||||
- La création et comparaison d'`Anagram`
|
||||
- Le tri des anagrammes par score
|
||||
|
||||
**Nombre de tests** : 10
|
||||
|
||||
### Tests d'intégration
|
||||
|
||||
#### integration_tests.rs
|
||||
Tests end-to-end qui vérifient :
|
||||
- Le flux complet de génération d'anagrammes
|
||||
- L'intégration entre l'analyseur et le générateur
|
||||
- La personnalisation du scorer via le trait
|
||||
- La configuration avancée
|
||||
- Les cas d'usage réels
|
||||
|
||||
**Nombre de tests** : 6
|
||||
|
||||
## Exécution des tests
|
||||
|
||||
### Exécuter tous les tests
|
||||
```bash
|
||||
cargo test
|
||||
```
|
||||
|
||||
### Exécuter un fichier de tests spécifique
|
||||
```bash
|
||||
cargo test --test analyzer_tests
|
||||
cargo test --test generator_tests
|
||||
cargo test --test types_tests
|
||||
cargo test --test integration_tests
|
||||
```
|
||||
|
||||
### Exécuter un test particulier
|
||||
```bash
|
||||
cargo test test_good_pronounceable_words
|
||||
```
|
||||
|
||||
### Exécuter avec sortie détaillée
|
||||
```bash
|
||||
cargo test -- --nocapture
|
||||
```
|
||||
|
||||
### Exécuter avec affichage des tests ignorés
|
||||
```bash
|
||||
cargo test -- --ignored
|
||||
```
|
||||
|
||||
### Voir la couverture de test (avec tarpaulin)
|
||||
```bash
|
||||
cargo install cargo-tarpaulin
|
||||
cargo tarpaulin --out Html
|
||||
```
|
||||
|
||||
## Métriques de tests
|
||||
|
||||
- **Total de tests** : 36 tests
|
||||
- Tests d'analyse : 11
|
||||
- Tests de génération : 9
|
||||
- Tests de types : 10
|
||||
- Tests d'intégration : 6
|
||||
|
||||
- **Couverture estimée** : ~90% du code
|
||||
|
||||
- **Temps d'exécution** : < 2 secondes pour tous les tests
|
||||
|
||||
## Principes de test appliqués
|
||||
|
||||
### 1. Tests indépendants
|
||||
Chaque test est autonome et n'affecte pas les autres. Utilisation de seeds fixes pour les générateurs aléatoires quand nécessaire.
|
||||
|
||||
```rust
|
||||
let rng = StdRng::seed_from_u64(42); // Reproductible
|
||||
```
|
||||
|
||||
### 2. Tests descriptifs
|
||||
Les noms de tests décrivent clairement ce qui est testé :
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn test_generation_produces_unique_anagrams() { ... }
|
||||
|
||||
#[test]
|
||||
fn test_common_consonant_clusters_not_penalized() { ... }
|
||||
```
|
||||
|
||||
### 3. Arrange-Act-Assert
|
||||
Structure claire des tests :
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn test_score_saturating_operations() {
|
||||
// Arrange
|
||||
let score = PronouncabilityScore::new(80);
|
||||
|
||||
// Act
|
||||
let increased = score.saturating_add(30);
|
||||
|
||||
// Assert
|
||||
assert_eq!(increased.value(), 100);
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Tests du comportement, pas de l'implémentation
|
||||
Focus sur le comportement observable plutôt que les détails d'implémentation.
|
||||
|
||||
### 5. Tests de cas limites
|
||||
Couverture des cas limites et d'erreur :
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn test_empty_string_scores_zero() { ... }
|
||||
|
||||
#[test]
|
||||
fn test_score_value_clamped_to_range() { ... }
|
||||
|
||||
#[test]
|
||||
fn test_generation_with_repeated_letters() { ... }
|
||||
```
|
||||
|
||||
## Écrire de nouveaux tests
|
||||
|
||||
### Pour ajouter un test d'analyse
|
||||
|
||||
Créer un nouveau test dans [tests/analyzer_tests.rs](tests/analyzer_tests.rs) :
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn test_new_phonetic_pattern() {
|
||||
let analyzer = PronounceabilityAnalyzer::with_defaults();
|
||||
|
||||
// Test du comportement attendu
|
||||
assert!(analyzer.score("example").value() > expected_threshold);
|
||||
}
|
||||
```
|
||||
|
||||
### Pour ajouter un test de génération
|
||||
|
||||
Créer un nouveau test dans [tests/generator_tests.rs](tests/generator_tests.rs) :
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn test_new_generation_behavior() {
|
||||
let rng = StdRng::seed_from_u64(42);
|
||||
let scorer = PronounceabilityAnalyzer::with_defaults();
|
||||
let mut generator = AnagramGenerator::new(rng, scorer);
|
||||
|
||||
let config = GenerationConfig::new(min_score, max_attempts);
|
||||
let anagrams = generator.generate("test", count, &config);
|
||||
|
||||
// Vérifications
|
||||
assert!(!anagrams.is_empty());
|
||||
}
|
||||
```
|
||||
|
||||
### Pour ajouter un test d'intégration
|
||||
|
||||
Créer un nouveau test dans [tests/integration_tests.rs](tests/integration_tests.rs) :
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn test_end_to_end_new_feature() {
|
||||
// Setup complet du système
|
||||
let rng = thread_rng();
|
||||
let scorer = PronounceabilityAnalyzer::with_defaults();
|
||||
let mut generator = AnagramGenerator::new(rng, scorer);
|
||||
|
||||
// Test du flux complet
|
||||
let config = GenerationConfig::new(50, 1000);
|
||||
let result = generator.generate("word", 5, &config);
|
||||
|
||||
// Vérifications end-to-end
|
||||
assert!(result.meets_requirements());
|
||||
}
|
||||
```
|
||||
|
||||
## Tests avec mocks et stubs
|
||||
|
||||
Pour tester l'injection de dépendances avec des scorers personnalisés :
|
||||
|
||||
```rust
|
||||
struct MockScorer {
|
||||
fixed_score: u32,
|
||||
}
|
||||
|
||||
impl PronounceabilityScorer for MockScorer {
|
||||
fn score(&self, _text: &str) -> PronouncabilityScore {
|
||||
PronouncabilityScore::new(self.fixed_score)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_mock_scorer() {
|
||||
let rng = thread_rng();
|
||||
let scorer = MockScorer { fixed_score: 100 };
|
||||
let mut generator = AnagramGenerator::new(rng, scorer);
|
||||
|
||||
// Tous les anagrammes auront un score de 100
|
||||
let config = GenerationConfig::new(99, 100);
|
||||
let anagrams = generator.generate("test", 5, &config);
|
||||
|
||||
assert!(anagrams.len() > 0);
|
||||
for anagram in anagrams {
|
||||
assert_eq!(anagram.score().value(), 100);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Stratégie de test pour les contributions
|
||||
|
||||
Lors de l'ajout de nouvelles fonctionnalités :
|
||||
|
||||
1. **Écrire les tests d'abord** (TDD)
|
||||
- Définir le comportement attendu
|
||||
- Écrire les tests qui échouent
|
||||
- Implémenter la fonctionnalité
|
||||
- Vérifier que les tests passent
|
||||
|
||||
2. **Couvrir les cas nominaux et d'erreur**
|
||||
- Cas nominal (happy path)
|
||||
- Cas limites (edge cases)
|
||||
- Cas d'erreur
|
||||
|
||||
3. **Maintenir l'isolation**
|
||||
- Pas de dépendances entre tests
|
||||
- Pas d'état partagé
|
||||
|
||||
4. **Tests rapides**
|
||||
- Éviter les I/O inutiles
|
||||
- Utiliser des seeds fixes pour le random
|
||||
- Pas de sleep() ou d'attente
|
||||
|
||||
## Continuous Integration
|
||||
|
||||
Le projet est prêt pour CI/CD. Configuration recommandée :
|
||||
|
||||
```yaml
|
||||
# .github/workflows/test.yml
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- run: cargo test --all-features
|
||||
- run: cargo test --doc
|
||||
```
|
||||
|
||||
## Debugging des tests
|
||||
|
||||
### Afficher la sortie des tests
|
||||
```bash
|
||||
cargo test -- --nocapture --test-threads=1
|
||||
```
|
||||
|
||||
### Exécuter avec le debugger
|
||||
```bash
|
||||
rust-gdb --args target/debug/deps/analyzer_tests-* test_name
|
||||
```
|
||||
|
||||
### Logs de débogage
|
||||
Utiliser `dbg!()` temporairement dans les tests :
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn test_debug() {
|
||||
let score = analyzer.score("test");
|
||||
dbg!(score); // Affiche la valeur
|
||||
assert!(score.value() > 50);
|
||||
}
|
||||
```
|
||||
|
||||
## Benchmark (optionnel)
|
||||
|
||||
Pour des benchmarks de performance, créer `benches/` :
|
||||
|
||||
```rust
|
||||
// benches/generation_benchmark.rs
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
|
||||
fn benchmark_generation(c: &mut Criterion) {
|
||||
c.bench_function("generate 10 anagrams", |b| {
|
||||
b.iter(|| {
|
||||
// Code à benchmarker
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, benchmark_generation);
|
||||
criterion_main!(benches);
|
||||
```
|
||||
|
||||
## Ressources
|
||||
|
||||
- [The Rust Book - Testing](https://doc.rust-lang.org/book/ch11-00-testing.html)
|
||||
- [Cargo Test Documentation](https://doc.rust-lang.org/cargo/commands/cargo-test.html)
|
||||
- [Integration Testing in Rust](https://doc.rust-lang.org/rust-by-example/testing/integration_testing.html)
|
||||
Reference in New Issue
Block a user