Search code examples
c#.netasync-awaitsonarqubevaluetask

SonarQube gives ValueTask instances returned from method calls should be directly awaited issue


In my .NET project test project I have method like this:

[Fact]
public async Task SampleMethod()
{
  // given
  Guid someRoleId = Guid.NewGuid();
  NpgsqlException npgsqlException = GetNpsqlException();

  var failedRoleStorageException = new FailedRoleStorageException(npgsqlException);

  var expectedRoleDependencyException = new RoleDependencyException(failedRoleStorageException);

  this.dataMock.SelectRoleByIdAsync(Arg.Any<Guid>()).Throws(npgsqlException);

  // when
  ValueTask<Role> roleByIdTask = this.roleService.RoleByIdAsync(someRoleId);

  // then
  RoleDependencyException actualServiceException = await Assert.ThrowsAsync < DependencyException > (() => roleByIdTask.AsTask());

  actualServiceException.Should().BeEquivalentTo(
  expectedRoleDependencyException);

  await this.dataMock.Received(1).SelectRoleByIdAsync(Arg.Any<Guid>());

  this.dataMock.ClearReceivedCalls();
}

In the above code this line gives me following SonarQube code smell.

ValueTask instances returned from method calls should be directly awaited, returned, or passed as an argument to another method call. Other usage, such as storing an instance into a local or a field, is likely an indication of a bug, as ValueTask instances must only ever be consumed once.

So I try to resolve it like this,

[Fact]
public async Task SampleMethod()
{
    // given
    Guid someRoleId = Guid.NewGuid();
    NpgsqlException npgsqlException = GetNpsqlException();

    var failedRoleStorageException = new FailedRoleStorageException(npgsqlException);
    var expectedRoleDependencyException = new RoleDependencyException(failedRoleStorageException);

    this.dataMock.SelectRoleByIdAsync(Arg.Any<Guid>()).Throws(npgsqlException);

    // when and then
    RoleDependencyException actualServiceException = await Assert.ThrowsAsync<RoleDependencyException>(
        () => this.roleService.RoleByIdAsync(someRoleId).AsTask());

    actualServiceException.Should().BeEquivalentTo(expectedRoleDependencyException);

    await this.dataMock.Received(1).SelectRoleByIdAsync(Arg.Any<Guid>());

    this.dataMock.ClearReceivedCalls();
}

In there I directly await the ValueTask without storing it in a variable. But it's also not the solution for me. How can I fix this issue?


Solution

  • Add .AsTask() at the end of your method.

    this.dataBrokerMock.SelectRoleByIdAsync(Arg.Any<Guid>()).AsTask().Throws(npgsqlException);
    

    https://rules.sonarsource.com/csharp/RSPEC-5034/