exercism / csharp

Exercism exercises in C#.
https://exercism.org/tracks/csharp
MIT License
333 stars 339 forks source link

Property based testing #2279

Open jpuriol opened 1 week ago

jpuriol commented 1 week ago

I believe it would be beneficial to add property-based tests to some of the exercises. This would ensure that students provide correct answers even for unusual edge cases. Have you considered this approach? I've already added property-based tests to the circular buffer exercise but am unsure how to contribute further.

github-actions[bot] commented 1 week ago

Hello. Thanks for opening an issue on Exercism 🙂

At Exercism we use our Community Forum, not GitHub issues, as the primary place for discussion. That allows maintainers and contributors from across Exercism's ecosystem to discuss your problems/ideas/suggestions without them having to subscribe to hundreds of repositories.

This issue will be automatically closed. Please use this link to copy your GitHub Issue into a new topic on the forum, where we look forward to chatting with you!

If you're interested in learning more about this auto-responder, please read this blog post.

ErikSchierboom commented 1 week ago

We have two such exercises:

jpuriol commented 1 week ago

Do you think these tests will improve the Circular Buffer exercise? I personally feel more confident about my implementation after running them, but I'm uncertain whether they cover more scenarios than the example-based tests. If you believe they add value, I can create a pull request to include them.

[Property]
public void WriteAndRead_ShouldWorkCorrectly(int capacity, int[] values)
{
    if (capacity <= 0 || values == null) return;

    var buffer = new CircularBuffer<int>(capacity);

    foreach (var value in values)
    {
        buffer.Write(value);
        Assert.Equal(value, buffer.Read());
    }
}

[Property]
public void WriteBeyondCapacity_ShouldThrowException(int capacity, int[] values)
{
    if (capacity <= 0 || values == null) return;

    var buffer = new CircularBuffer<int>(capacity);

    foreach (var value in values)
    {
        if (buffer.Size < capacity)
        {
            buffer.Write(value);
        }
        else
        {
            Assert.Throws<InvalidOperationException>(() => buffer.Write(value));
        }
    }
}

[Property]
public void ReadFromEmptyBuffer_ShouldThrowException(int capacity)
{
    if (capacity <= 0) return;

    var buffer = new CircularBuffer<int>(capacity);
    Assert.Throws<InvalidOperationException>(() => buffer.Read());
}

[Property]
public void Overwrite_ShouldReplaceOldestValue(int capacity, int[] values)
{
    if (capacity <= 0 || values == null) return;

    var buffer = new CircularBuffer<int>(capacity);

    foreach (var value in values)
    {
        buffer.Overwrite(value);
    }

    for (int i = Math.Max(0, values.Length - capacity); i < values.Length; i++)
    {
        Assert.Equal(values[i], buffer.Read());
    }
}

[Property]
public void Clear_ShouldResetBuffer(int capacity, int[] values)
{
    if (capacity <= 0 || values == null) return;

    var buffer = new CircularBuffer<int>(capacity);

    foreach (var value in values)
    {
        if (buffer.Size < capacity)
        {
            buffer.Write(value);
        }
    }

    buffer.Clear();
    Assert.Throws<InvalidOperationException>(() => buffer.Read());
}