ClassCleanupBehavior.EndOfClass causes Microsoft.AspNetCore.Mvc.Testing based tests to fail with TaskCanceledException: The operation was canceled.
Describe the bug
Test which use an in-memory ASP.NET Core web server and linked HTTP client started failing with the following exception after I replaced [ClassCleanup] with [ClassCleanupBehavior.EndOfClass] per MSTEST0034:
Failed DeleteAccount_Should_Return_Ok [135 ms]
Error Message:
Test method Provisioning.Service.Tests.Functional.Controllers.DataControllerTests.DeleteAccount_Should_Return_Ok threw exception:
System.Threading.Tasks.TaskCanceledException: The operation was canceled. ---> System.Net.Http.HttpRequestException: Error while copying content to a stream. ---> System.IO.IOException: ---> System.IO.IOException: The client aborted the request.
Stack Trace:
at Microsoft.AspNetCore.TestHost.ResponseBodyReaderStream.CheckAborted()
at Microsoft.AspNetCore.TestHost.ResponseBodyReaderStream.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
at System.IO.Stream.<CopyToAsync>g__Core|27_0(Stream source, Stream destination, Int32 bufferSize, CancellationToken cancellationToken)
at System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task serializeToStreamTask, MemoryStream tempBuffer)
--- End of inner exception stack trace ---
at System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task serializeToStreamTask, MemoryStream tempBuffer)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.HttpClient.HandleFailure(Exception e, Boolean telemetryStarted, HttpResponseMessage response, CancellationTokenSource cts, CancellationToken cancellationToken, CancellationTokenSource pendingRequestsCts)
at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
at Provisioning.Service.Tests.Functional.Controllers.DataControllerTests.SendAsync[T](HttpMethod httpMethod, Uri url, T resource) in C:\__w\1\s\src\Provisioning\Service.Tests.Functional\Controllers\DataControllerTests.cs:line 103
at Provisioning.Service.Tests.Functional.Controllers.DataControllerTests.DeleteAccount_Should_Return_Ok() in C:\__w\1\s\src\Provisioning\Service.Tests.Functional\Controllers\DataControllerTests.cs:line 45
Steps To Reproduce
[TestClass]
public class DataControllerTests
{
protected static WebApplicationFactory<Program> _app;
protected static HttpClient _httpClient;
[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
_app = new WebApplicationFactory<Program>()
.WithWebHostBuilder(builder => builder.ConfigureServices(s =>
{
// setting up some mocks
})
.UseEnvironment(Environments.Development));
_httpClient = _app.CreateDefaultClient();
}
[ClassCleanup(ClassCleanupBehavior.EndOfClass)] // <-- !
public static void ClassCleanup() =>
_app.Dispose();
[TestMethod]
public async Task DeleteAccount_Should_Return_Ok()
{
var account = CreateAccount();
var url = new Uri($"/data/accounts/{account.Name}", UriKind.Relative);
// Act
using var response = await SendAsync(HttpMethod.Delete, url, account);
// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);
}
private static Account CreateAccount() =>
new Account(); // simple POCO
private async Task<HttpResponseMessage> SendAsync<T>(
HttpMethod httpMethod,
Uri url,
T resource)
where T : class
{
var request = new HttpRequestMessage(httpMethod, url)
{
Content = new JsonContent(resource)
};
return await _httpClient.SendAsync(request, this.TestContext!.CancellationTokenSource.Token);
}
}
Expected behavior
The tests continue working as before.
Actual behavior
See above.
Additional context
Test project:
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Platform>AnyCPU</Platform>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
NuGet packages:
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.11" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="MSTest.TestAdapter" Version="3.7.0" />
<PackageVersion Include="MSTest.TestFramework" Version="3.7.0" />
<GlobalPackageReference Include="MSTest.Analyzers" Version="3.7.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</GlobalPackageReference>
Hi @abatishchev,
Could you please share a full example? From the partial code, I am not able to reproduce the issue so I am probably not setuping things the same way you do. For example, are you using MSTest runner or still VSTest?
Let me add an important detail (which however makes it harder to investigate the issue): the errors occur exclusively in an ADO pipeline (I shared a link with you privately).
Also let me attach a better, fully working (compiling, but not failing) code: TestProject8.zip
Closing as there is not enough info to reproduce and investigate the issue.