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?
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);