Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C#, xunit, fscheck, writing a simple property based test using a custom generator or constrained random string

I am trying to solve the diamond kata in order to learn how to write property based tests with the fscheck library. I want to write the tests with C# and I am using Visual Studio 2017.

I want to write a property based test that does not generate any random chars as input, but letters only. I'm not sure how to write the generator fscheck requires to do this and in which file to put the code?

I searched everywhere and read documentation, but am having trouble (partly because I cannot translate F# into C# very well).

How is [Property] used to constrain the input data to only letters?

If there is a better approach please let me know.

[Edit:]

I edited my code examples, which now contain one working solution by Kurt Schelfthout .



Tests

using DiamondKata;
using FsCheck;
using FsCheck.Xunit;
using Xunit;

namespace DiamondKataTests
{
    public static class Arbitraries
    {
        private static readonly string upperAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        private static readonly string lowerAlphabet = ""; //upperAlphabet.ToLower();
        private static readonly char[] wholeAlphabet = (lowerAlphabet + upperAlphabet).ToCharArray();
        public static Arbitrary<char> LetterGenerator()
        {
            return Gen.Elements(wholeAlphabet).ToArbitrary();
        }
    }

    public class DiamondKataTests
    {
        // THIS WORKS and is apparently the preferred way of doing things
        // also see here: https://stackoverflow.com/questions/32811322/fscheck-in-c-generate-a-list-of-two-dimension-arrays-with-the-same-shape
        [Property()]
        public Property shouldReturnStringAssumesValidCharWasProvided()
        {
            return Prop.ForAll(Arbitraries.LetterGenerator(), letter =>

                // test here
                Assert.NotNull(Diamond.Create(letter))
            );
        }

        // Second solution ...
        // Error here: Arbitraries is a type not valid in the given context
        [Property(Arbitrary = new[] { typeof<Arbitraries> })]
        public void testThatAssumesValidCharWasProvided(char lettersOnlyHERE)
        {
            // ?
        }
    }
}

Class To Test

namespace DiamondKata
{
    public class Diamond
    {
        public static string Create(char turningPointCharacter)
        {
            return "";
        }
    }
}
like image 707
Shakka Avatar asked Nov 07 '25 10:11

Shakka


1 Answers

You can't put constraints in attributes, the types that you can pass to an attribute are just to limited to do that.

You have a few options. You can define a custom Arbitrary instance for char, i.e. an implementation of Arbitrary<char> and configure the property to use that.

public static class Arbitraries
{
    public static Arbitrary<char> LetterGenerator()
    {
        return Gen.Elements(wholeAlphabet).ToArbitrary();
    }
}

public class DiamondKataTestClass1
{
    [Property(Arbitrary=new[] { typeof<Arbitraries> })]
    public void testThatAssumesValidCharWasProvided(char lettersOnlyHERE)
    {
        // ?
    }
}

You can also use the more flexible API to customize the generator inline:

public class DiamondKataTestClass1
{
    [Property()]
    public Property testThatAssumesValidCharWasProvided()
    {
        Prop.ForAll(Arbitraries.LetterGenerator()) (letter =>
        // test here
        )
    }
}
like image 160
Kurt Schelfthout Avatar answered Nov 10 '25 01:11

Kurt Schelfthout



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!