-
-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Async Task in Multiple Tests #1456
Comments
This should actually work, as far as I can tell. When you call However, you may want to change the code slightly, to ensure that changes to await InvokeAsync(() =>
{
// set other data.
loading = false;
StateHasChanged();
}); This should ensure that the changes you are making in your UI component get dispatched back to the UI thread at a point when the UI thread is free to observe the changes. If the background task is looong running, you can change the timeout for the WaitFor like so. subject.WaitForAssertion(() => _subject.Find(".assert-data"), TimeSpan.FromSeconds(5)); An alternative is to replace the background work being done by a test double that just returns data immediately. That way you are testing your UI functionality in isolation from the background work being done. |
Thanks for the response. I will test this out today and confirm whether it works or not. If it is still giving me trouble I will try and recreate this in a simpler component I can share here. All of our data retrieval methods are being mocked, and their return values should be returning immediately. I did think it was possible we forgot to mock a return value, and the test was getting stuck there, but I've confirmed all data requests are in fact mocked and have a specified return value. |
Question: What are your reasons for spinning up a task on another thread? Why not just do: protected override async Task OnInitializedAsync()
{
loading = true;
await Task.WhenAll(
...async work being done,
...async work to be done on separate thread);
loading = false;
} |
So the UI thread can release while other work is completed. I do also get similar test failures if I await our |
the UI thread is free to run either way, I do not think you get any benefit of explicitly using Task.Run. However, when you do, you have to be careful about where continuations are run, what scheduler is being used. I have never had any reason to do this in my blazor apps, even for slow database queries. |
That is, I dont think you are getting the benefit you think by doing Task.Run.
This works just as well, as far as I know. |
In testing in my particular use case I've found that |
Not true. It will block the rest of the initialization method from running, but the component still completes a render cycle. Take for example this sample component from standard Blazor template: @page "/weather"
@attribute [StreamRendering]
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates showing data.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
// Simulate asynchronous loading to demonstrate streaming rendering
await Task.Delay(500);
var startDate = DateOnly.FromDateTime(DateTime.Now);
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
}).ToArray();
}
private class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
} This will complete a render cycle and render In other words, you are not achieving what you think you are by creating task with Task.Run and not awaiting them. Learn more here: https://learn.microsoft.com/en-us/aspnet/core/blazor/components/lifecycle?view=aspnetcore-8.0 |
Describe the bug
Testing component with
Task.Run
inside ofasync Task OnInitializedAsync
results in intermittent test failures. When running the test by itself, it will always succeed. When running with all other tests in the class, certain tests will intermittently fail. It's important to note below is an example of what we see causing, we have 14 tests inside our tests class, verifying different aspects of functionality. The tests themselves and the component are more robust, and I can added in a more detailed example if need be. We've also attempted to use bothWaitForState
andWaitForAssertion
in both cases, neither results in the expected behavior. Additionally, adding timespans of upwards of 15 seconds has not fixed the behavior either.I assume this has something to do with trying to run multiple threads with the tests and some asynchronous action locking the completion of the task.
I've verified:
_ = Task.Run
and doing all that work inside the initialization results in the tests passing every time.dotnet tests
command.Example:
Testing this component:
With this test:
Results in this output:
Expected behavior:
I expect the test passes every single time, whether ran individually or ran with all other tests.
Version info:
Additional context:
Using XUnit, FluentAssertions, and MOQ.
The text was updated successfully, but these errors were encountered: