| Property | Value |
|---|---|
| Category | Reproducibility (JustDummies.Reproducibility) |
| Severity | 🔴 Error |
| Enabled by default | Yes |
Any.Reproducibly takes a synchronous Action. An async lambda bound to it becomes async void: the body runs to its first await, then its continuation — every assertion after that await — runs after the call has already returned, and the exception escapes the reproducible scope entirely. The test passes green even though the body failed.
Pass the asynchronous body to Any.ReproduciblyAsync(Func<Task>) and await it. For a synchronous body, keep Any.Reproducibly(() => { ... }).
Noncompliant
[Fact]
public void A_20_percent_discount_takes_a_fifth_off_the_order() {
Any.Reproducibly(async () => { // JD001: the async body runs as '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); // this failure never reaches the test runner
});
}
Compliant
[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);
});
}