Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check return value in FluentAssertion exception syntax

I'd like to check the return value from the method by FluentAssertion syntax. Please consider the following snippet:

public interface IFoo
{
    Task<int> DoSomething();
}

public class Bar
{
    private readonly IFoo _foo;
    private static int _someMagicNumber = 17;

    public Bar(IFoo foo)
    {
        _foo = foo;
    }

    public async Task<int> DoSomethingSmart()
    {
        try
        {
            return await _foo.DoSomething();
        }
        catch
        {
            return _someMagicNumber;
        }
    }
}

[TestFixture]
public class BarTests
{
    [Test]
    public async Task ShouldCatchException()
    {
        // Arrange
        var foo = Substitute.For<IFoo>();
        foo.DoSomething().Throws(new Exception());
        var bar = new Bar(foo);
        Func<Task> result = () => bar.DoSomethingSmart();

        // Act-Assert
        await result.Should().NotThrowAsync();
    }

    [Test]
    public async Task ShouldReturnDefaultValueWhenExceptionWasThrown()
    {
        // Arrange
        var foo = Substitute.For<IFoo>();
        foo.DoSomething().Throws(new Exception());
        var bar = new Bar(foo);

        // Act
        var result = await bar.DoSomethingSmart();

        // Assert
        result.Should().Be(17);
    }
}

My goal is combining those two tests into the new one, but I'd like to preserve the fluent assertion check: result.Should().NotThrowAsync();

So my question is how to check in the first test that the return value is 17 in my example?

like image 767
rgb Avatar asked Sep 16 '26 04:09

rgb


1 Answers

The current version of Fluent Assertions (5.5.3) does not distinguish between Func<Task> and Func<Task<T>>. Both types are handled by AsyncFunctionAssertions, which assigns it to a Func<Task> and hence looses the return value for Task<T>.

One way to circumvent this, is to assign the return value to a local variable.

[Test]
public async Task ShouldCatchException()
{
    // Arrange
    var foo = Substitute.For<IFoo>();
    foo.DoSomething().Throws(new Exception());
    var bar = new Bar(foo);

    // Act
    int? result = null;
    Func<Task> act = async () => result = await bar.DoSomethingSmart();

    // Act-Assert
    await act.Should().NotThrowAsync();
    result.Should().Be(17);
}

I've created an issue on the Fluent Assertion issue tracker.

edit:

Fluent Assertions 6.0.0 added support for Task<T>, so you can continue asserting on the result of DoSomethingSmart.

// Arrange
var foo = Substitute.For<IFoo>();
foo.DoSomething().Throws(new Exception());
var bar = new Bar(foo);

// Act
Func<Task<int>> act = () => bar.DoSomethingSmart();

// Act-Assert
(await act.Should().NotThrowAsync()).Which.Should().Be(17);

There's also a new neat helper WithResult for async methods to avoid the extra set of parentheses.

// Arrange
var foo = Substitute.For<IFoo>();
foo.DoSomething().Throws(new Exception());
var bar = new Bar(foo);

// Act
Func<Task<int>> act = () => bar.DoSomethingSmart();

// Act-Assert
await act.Should().NotThrowAsync().WithResult(17);
like image 100
Jonas Nyrup Avatar answered Sep 17 '26 18:09

Jonas Nyrup



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!