4

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 "";
        }
    }
}
Shakka
  • 137
  • 8

1 Answers1

4

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
        )
    }
}
Kurt Schelfthout
  • 8,880
  • 1
  • 30
  • 48
  • thanks so much for your response, unfortunately your solutions give me errors. I edited the above post which now include your code and comments where i get errors ... thanks! – Shakka Oct 23 '17 at 07:00
  • found the fix for one of the errors myself, your syntax was slightly off, i took the liberty and edited your solution, thank you again! – Shakka Oct 23 '17 at 07:26