| Propriété | Valeur |
|---|---|
| Catégorie | Reproductibilité (JustDummies.Reproducibility) |
| Sévérité | 🔴 Erreur |
| Activée par défaut | Oui |
Any.Reproducibly prend une Action synchrone. Une lambda async qui s’y lie devient async void : le corps s’exécute jusqu’à son premier await, puis sa continuation — chaque assertion après cet await — s’exécute après le retour de l’appel, et l’exception échappe entièrement à la portée reproductible. Le test passe au vert alors même que le corps a échoué.
Passez le corps asynchrone à Any.ReproduciblyAsync(Func<Task>) et faites await. Pour un corps synchrone, gardez Any.Reproducibly(() => { ... }).
Non conforme
[Fact]
public void A_20_percent_discount_takes_a_fifth_off_the_order() {
Any.Reproducibly(async () => { // JD001 : le corps async s'exécute en 'async void'
string anyReference = Any.String().StartingWith("ORD-").WithLength(12).Generate();
string anyCustomer = Any.String().Alpha().WithLengthBetween(1, 50).Generate();
Order order = new Order(anyReference, anyCustomer, amount: 100m);
order.ApplyDiscount(20);
await _repository.SaveAsync(order);
Assert.Equal(80m, order.Total); // cet échec n'atteint jamais le lanceur de tests
});
}
Conforme
[Fact]
public async Task A_20_percent_discount_takes_a_fifth_off_the_order() {
await Any.ReproduciblyAsync(async () => {
string anyReference = Any.String().StartingWith("ORD-").WithLength(12).Generate();
string anyCustomer = Any.String().Alpha().WithLengthBetween(1, 50).Generate();
Order order = new Order(anyReference, anyCustomer, amount: 100m);
order.ApplyDiscount(20);
await _repository.SaveAsync(order);
Assert.Equal(80m, order.Total);
});
}