hedgehogqa / fsharp-hedgehog

Release with confidence, state-of-the-art property testing for .NET.
https://hedgehogqa.github.io/fsharp-hedgehog/
Other
271 stars 31 forks source link

Can `.CheckAsync` exist in C# world? #449

Open AlexeyRaga opened 9 months ago

AlexeyRaga commented 9 months ago

I stumbled upon a need to test an async action in C#, like:

var property =
      from schoolId in Property.ForAll(Gen.Guid.NoShrink())
      from registered in Property.ForAll(SchoolRegistered(schoolId))
      select handler.Handle(null!, registered);

It'd be great to be able to run this property with something like .CheckAsync()

AlexeyRaga commented 1 month ago

Is there a better way of writing it than this?

    public static Task CheckAsync(this Property<Task> property)
    {
        property
            .Select(x => x.GetAwaiter().GetResult())
            .Check();
        return Task.CompletedTask;

    }

    public static Task CheckAsync(this Property<Task<bool>> property)
    {
        property
            .Select(x => x.GetAwaiter().GetResult())
            .Check();
        return Task.CompletedTask;
    }

I don't like it, but I saw that Hedgehog.Xunit does the same trick so I assumed that it'd be the only way that is currently supported?

If we are settling on this approach, can these methods be added to the library please?

TysonMN commented 1 month ago

What are you property testing that involves Task?

AlexeyRaga commented 1 month ago

Many things. Anything involving combinators or operations with IAsyncEnumerable is one example. I use it a lot in event streaming/sourcing scenarios.

Many interfaces now provide only async API to accommodate different backends. My line of work stuff includes Cache, Outbox and Producer interfaces.

Using testing harness with async API, for example, HotChocolate GraphQL executors: register types, generate the query, see that it is understood and parsed by HotChocolate correctly and into correct values. That has an async API.

I also use property based testing for integration tests from time to time, very handy, too.

Like, make an API call, make sure that a correct message is published to a Kafka topic and that the schema is registered in the registry, but only once per schema.

Or testing projectors: giving it a generated message and then asserting that it was projected in an expected format at the expecting place...

There are many scenarios. And I don't think that conceptually not supporting testing async functions would have a good justification. Especially knowing that Hedgehog.XUnit already supports it.

Granted being able to sequence Property<Async<'T>> ->Async<Property<'T>>would be awesome, but I assume that it'd be much more work than just awaiting, and that's whyHedgehog.XUnit` makes this choice...