loading...
Cover image for Input generators in property-based tests with FsCheck

Input generators in property-based tests with FsCheck

mbernard profile image Miguel Bernard Originally published at blog.miguelbernard.com ・3 min read

Property-based testing (5 Part Series)

1) What's wrong with the current state of unit testing 2) How many unit tests are good enough | Property-Based testing 3) How to get started with Property-based Testing in C# 4) Input generators in property-based tests with FsCheck 5) First and Last line content | Solving the diamond kata with property-based testing

Solving the diamond kata with property-based testing series

  1. How to get started with Property-based Testing in C#
  2. Input generators in property-based tests with FsCheck
  3. First and Last line content
  4. Height equals Width
  5. Outside space symmetry
  6. Symmetry around the vertical axis
  7. Symmetry around the horizontal axis
  8. No padding for input letter row
  9. Letters order

All code samples are available on github


Intro

Now that we have all the tools installed, we are finally ready to write our first Property-Based test.

FsCheck

Creating a property-based test is as simple as tagging a method with the [Property] attribute, similarly as you would do in xUnit with the [Fact] or [Theory] attributes. If you dig a little, you will realize that there's a lot of configurable options on the [Property] attribute. You can control how many random tests will be run each time, timeouts, etc. One of them is essential; the Arbitrary property. That property will define which method to use to generate random inputs. In our specific case, we are not interested in all the possible values of char. We only care about the 26 letters of the alphabet. To scope the input, we'll need to configure a generator that will do just that.

Generators

Generators are relatively simple.

  1. Create a static class
  2. Add a static method that returns Arbitrary<TypeYouWantToGenerateValueFor>
  3. Voilà

You can write your randomization logic, but it's usually better to start from the built-in methods as they are already well balanced.

public static class LetterGenerator
{
    public static Arbitrary<char> Generate() =>
            Arb.Default.Char().Filter(c => c >= 'A' && c <= 'Z');
}

Not Empty Test

It may seem basic, but it's quite essential. We want to make sure we always have a non-empty result.

[Property(Arbitrary = new[] { typeof(LetterGenerator) })]
public Property NotEmpty(char c)
{
    return Diamond.Generate(c).All(s => s != string.Empty).ToProperty();
}

One thing I forgot to mention earlier, the test method also needs to return a property object. Fortunately for us, the library contains an extension method that can transform any boolean expression into a property object by calling ToProperty().

So our test reads like this:

  • Call the Diamond.Generate() method with the provided input char c.
  • Make sure all the lines of the returned diamond are not empty.
  • Use the ToProperty() method to wrap it into a property object.

Stay tuned

Stay tuned for my next posts on this series about solving the diamond kata with property-based testing. The following post will try to define properties for the first and last lines of our diamond.


Solving the diamond kata with property-based testing series

  1. How to get started with Property-based Testing in C#
  2. Input generators in property-based tests with FsCheck
  3. First and Last line content
  4. Height equals Width
  5. Outside space symmetry
  6. Symmetry around the vertical axis
  7. Symmetry around the horizontal axis
  8. No padding for input letter row
  9. Letters order

All code samples are available on github

Property-based testing (5 Part Series)

1) What's wrong with the current state of unit testing 2) How many unit tests are good enough | Property-Based testing 3) How to get started with Property-based Testing in C# 4) Input generators in property-based tests with FsCheck 5) First and Last line content | Solving the diamond kata with property-based testing

Posted on by:

mbernard profile

Miguel Bernard

@mbernard

Miguel has over 10 years of experience with Microsoft Technologies. Specialized with many things in the Microsoft ecosystem, including C#, F#, and Azure

Discussion

markdown guide