Question: how to create dependent properties?
See original GitHub issueHi all,
I want to write a test for a method that takes a non-empty collection of positive numbers double[]
, and a double targetSum
, and finds the shortest combination of numbers in the collection, whose sum is >= targetSum * 0.95
and <= targetSum * 1.15
.
My attempt looks like this:
public static class Generators
{
public static Arbitrary<double[]> Doubles()
{
return Gen.NonEmptyListOf(Arb.Generate<double>()
.Where(x => x >= 2 && x <= 20))
.Select(x => x.ToArray()).ToArbitrary();
}
}
public class Tests
{
[Property(Arbitrary = new[] { typeof(Generators) })]
public void FindBestSessionsTest(double[] values, double targetSum)
{
var result = FindBestCombination(values, targetSum);
result.Should().NotBeEmpty();
var sum = result.Sum();
sum.Should().BeGreaterThanOrEqualTo(targetSum * 0.95)
.And.BeLessThanOrEqualTo(targetSum * 1.15);
}
}
I cannot figure out how to create a generator that will create a targetSum. The strategy I think should work is to pick one or more numbers from the values
input array, sum them together, and then take the resulting exact targetSum and shift it up/down within the legal range targetSum * 0.95
and targetSum * 1.15
. My idea is that FsCheck should try to find a targetSum
that should be possible for FindBestCombination
to find but cannot.
Any suggestions would be much appreciated by an FsCheck newbie!
Issue Analytics
- State:
- Created 6 months ago
- Comments:13 (8 by maintainers)
I don’t think there’s anything wrong with the specific solution you’ve arrived at. I just find problems like these interesting because they seem to expose that there are more layers beneath the first one.
The approach that you’re currently taking is the first layer, and, again, there’s nothing wrong with it. Frequently, I stop there. Essentially, what you’re doing is that you’ve identified an equivalence class and now the problem has become: How to draw inputs from that equivalence class as faithfully as possible.
Sometimes, a next level is available. This is where you identify properties that hold for the entire domain of the function. This relieves you from the often awkward arrangement of the equivalence class, so it makes the tests simpler and also tends to make them more robust to changes. My blog has an example: Property-based testing is not the same as partition testing.
A third layer then sometimes follows where you begin to realise that (part of) what remains in terms of expressing the domain of the function can be expressed as types rather than FsCheck combinators. (Trivial example: Use a (hypothetical)
NonEmptyCollection<T>
instead of an array.) This once again makes the tests simpler, and also the SUT safer (à la poka-yoke).Based on what you can divulge, I can’t see what opportunities exist, so we can just leave it at that.
@Egil mostly a question of preference? Sometimes (as in the first iteration) one or the other turns out much simpler. I haven’t put much deep thought in it. I think @ploeh might have a much more considered opinion or alternative.