I started looking at FsCheck yesterday, and I am trying to write a simple test, that any instance of DiscountAmount will always have negative value. My question is, is it ok to have multiple asserts within one test. For example, here I am saying that amount from which discountAmount has been created plus discount amount should be 0. But I also say that discount amount should be less than 0. Should this be 2 tests or 1?
public class DiscountAmountTests
{
[Property()]
public void value_or_created_discountAmount_should_be_negative()
{
Arb.Register<AmountArbitrary>();
Prop.ForAll<Amount>(
v =>
{
var sut = new DiscountAmount(v);
var expectedResult = 0;
var result = v + sut;
result.Should().Be(expectedResult);
sut.Value.Should().BeLessThan(0);
})
.QuickCheckThrowOnFailure();
}
public class AmountArbitrary
{
public static Arbitrary<Amount> Amounts()
{
return Arb.Generate<decimal>().Where(x => x > 0)
.Select(x => new Amount(x))
.ToArbitrary();
}
}
}
}
I would say this is really up to you. I think there are arguments pro and cons - on the one hand, sometimes setup cost is expensive (be it in terms of programmer work to get the system into a particular state, or really compute resource cost, e.g. you have to do a expensive query to the DB or something) and then in my opinion it's worth making tests more coarsely grained.
The trade-off is that it's typically less clear what the problem is if a coarse grained test fails.
In comparison with unit tests, FsCheck has a bit more setup costs in terms of argument generation, and it is attractive to make FsCheck tests more coarse-grained than unit tests. Also note that FsCheck has some methods like Label
, And
. Or
to combine different properties together while sharing the argument generation, and still allow you to see what part of your test fails, somewhat off-setting one downside.