Closed mikes-gh closed 3 years ago
We are using WaitForAssertion in some of our tests.
Thanks for reporting this. I am investigating a very specific test case in bUnit's test suite which always fail on linux, but never on windows.
Can you read through #329 and see if there is an overlap in the tests you are seeing fail and the one describe in that.
I already read it. I was thinking that maybe the WaitForAssertion maybe causing subsequent tests to fail. In particular one of the WaitForAssertion's that we use takes a relatively long time 200ms because we have a delay set in the component to make the UI look better. However we seem to differ in that I think my problems started happening after moving to net 5.0 whereas you are seeing this on netcoreapp3.1 only.
Interestingly if you look at the markup from the Console.Writeline you will see that the element bUnit doesn't find is definitely there. I seem to remember an issue like this earlier that preview 01 resolved. edit or it might have been beta 11
It was this issue https://github.com/egil/bUnit/issues/290
A few things I would like to have confirmed:
With this, and the #329 issue, that only seems to affect Linux, it might have something to do with how the default dispatcher works on Linux.
I might have to set up a VS code instance running on Linux to be able to debug this more easily...
Thanks for clarifying @mikes-gh.
As for the WaitFor methods... you might need to use them when you have async operations that trigger the renders in the component, otherwise you are likely to see this issue that randomly shows up. That is expected, because the test code runs in its own thread, and the renderer runs in another. And if you trigger something from the test thread, e.g. by clicking a button, that causes the renderer to schedule a async render, e.g. due to a Task.Delay
call, then you most definently need to use one of the WaitFor methods.
You can read more about it here https://bunit.egilhansen.com/docs/interaction/awaiting-async-state.html and here https://bunit.egilhansen.com/docs/verification/async-assertion.html
@egil
Understood For our docs website we run all the docs through a render in bUnit just to check they have no errors rendering.
I recently added some table examples that use a web service in OnInitialiseAsync to fetch data. I have seen errors in those tests occasionally. Is this OK?
@using System.Net.Http.Json
@using MudBlazor.Examples.Data.Models
@namespace MudBlazor.Docs.Examples
@inject HttpClient httpClient
<MudTable Items="@Elements.Take(4)" Hover="true" Breakpoint="Breakpoint.Sm">
<HeaderContent>
<MudTh>Nr</MudTh>
<MudTh>Sign</MudTh>
<MudTh>Name</MudTh>
<MudTh>Position</MudTh>
<MudTh>Molar mass</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Nr">@context.Number</MudTd>
<MudTd DataLabel="Sign">@context.Sign</MudTd>
<MudTd DataLabel="Name">@context.Name</MudTd>
<MudTd DataLabel="Position">@context.Position</MudTd>
<MudTd DataLabel="Molar mass">@context.Molar</MudTd>
</RowTemplate>
</MudTable>
@code {
private IEnumerable<Element> Elements = new List<Element>();
protected override async Task OnInitializedAsync()
{
Elements = await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
}
}
[Test]
public void TableBasicExample_Test()
{
ctx.RenderComponent<TableBasicExample>();
}
If my assumption that await httpClient.GetFromJsonAsync<List<Element>>("webapi/periodictable");
doesn't complete immediately, then you need to do a WaitFor*.
What happens is that you will see two renders, the first where there is no items in the Elements
list, and then, async in the renderers thread, when the awaited http call returns.
You can either use WaitForState or WaitForAssertion, depending on what you are trying to do (there is a WaitForElement #252 planned).
E.g.:
[Test]
public void TableBasicExample_Test()
{
var cut = ctx.RenderComponent<TableBasicExample>();
cut.WaitForState(() => cut.FindAll("tbody tr").Count > 0);
}
But if I only need to know it renders without error can I just let if fly?
But if I only need to know it renders without error can I just let if fly?
Yes, you can, but that would verify that it renders with content, only that is able to render an empty list.
Question: Is that an example of a test that fails?
I did get this exception. Strange thing is it was a real failure due to the casing of the url but it had sat without causing an exception for a long while before. At what point does the test conclude in the situation above?
A total of 1 test files matched the specified pattern.
Failed TableBasicExample_Test [25 ms]
Error Message:
System.Net.Http.HttpRequestException : Response status code does not indicate success: 404 (No matching mock handler for "GET https://localhost/webapi/periodicTable").
Stack Trace:
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at System.Net.Http.Json.HttpClientJsonExtensions.GetFromJsonAsyncCore[T](Task`1 taskResponse, JsonSerializerOptions options, CancellationToken cancellationToken)
at MudBlazor.Docs.Examples.TableBasicExample.OnInitializedAsync() in /home/vsts/work/1/s/src/MudBlazor.Docs/Pages/Components/Table/Examples/TableBasicExample.razor:line 28
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)
at Bunit.Rendering.TestRenderer.AssertNoUnhandledExceptions() in /_/src/bunit.core/Rendering/TestRenderer.cs:line 280
at Bunit.Rendering.TestRenderer.Render[TResult](RenderFragment renderFragment, Func`2 activator) in /_/src/bunit.core/Rendering/TestRenderer.cs:line 164
at Bunit.Rendering.TestRenderer.RenderFragment(RenderFragment renderFragment) in /_/src/bunit.core/Rendering/TestRenderer.cs:line 38
at Bunit.Extensions.TestContextExtensions.RenderInsideRenderTree[TComponent](TestContextBase testContext, RenderFragment renderFragment) in /_/src/bunit.web/Extensions/TestContextExtensions.cs:line 20
at Bunit.TestContext.Render[TComponent](RenderFragment renderFragment) in /_/src/bunit.web/TestContext.cs:line 61
at Bunit.TestContext.RenderComponent[TComponent](ComponentParameter[] parameters) in /_/src/bunit.web/TestContext.cs:line 36
at MudBlazor.UnitTests.Components.ExampleDocsTests.TableBasicExample_Test() in /home/vsts/work/1/s/src/MudBlazor.UnitTests/Generated/ExampleDocsTests.generated.cs:line 1124
Skipped DatePicker_Render_Performance [< 1 ms]
Skipped Open_Close_DateRangePicker_10000_Times_CheckPerformance [< 1 ms]
Skipped RenderDateRangePicker_10000_Times_CheckPerformance [< 1 ms]
Also I just reran that test with a completely incorrect url and it passes.
It seems to me that there is different threading behaviour on the build server. BTW I am using macOS at the moment. I cant get that same test to fail locally.
At what point does the test conclude in the situation above? ... Also I just reran that test with a completely incorrect url and it passes.
In this case, it looks like the RenderComponent
method throws, as the httpClient.GetFromJsonAsync
throws because of a 404 response. So in this case the error happens before the RenderComponent
method returns.
That test error has nothing to do with bUnit though. The exception comes from HttpClient, so that is what you should focus on in this particular case (not saying bUnit not at fault other places). That code would fail with the same exception in a Blazor app, unless HttpClient works differently on Unix vs in the Blazor WASM/Blazor Server.
I think I am wasting your time a bit here. I probably need to take stock and wait for another error. At that point I think I will open a new issue. What do you think?
I think I am wasting your time a bit here.
Not necessarily. But you are always welcome to create an issue, or if you simply have at test that you do not understand why it fails, a good place is to post a question with the test, component under test, and output in https://github.com/egil/bUnit/discussions.
Shall we close this issue for now?
Yes I will close. When I have another seemingly random failure I will do my best to tie it down. Certainly there is something going on on the build server that is not happening locally. Whether it be through poorly written tests or some complex threading issues I am not sure.
I had another seemingly random failure but it was this. We render all our docs examples to check for errors. We don't test any assertions. We mock api for http content retrieval using a MockHttpHandler, Every now and then I got an exception . I didn't know why. But when I tested the MockHttpHandler directly it failed every time. I had an incorrect content type. Why does the thread not synchronise with the await call and bubble the exception back to the test thread?
var response = await HttpClient.GetAsync("https://raw.githubusercontent.com/Garderoben/MudBlazor/master/LICENSE");
LicenseText = await response.Content.ReadAsStringAsync();
This is the example
@using System.Net
@using System.Text
@namespace MudBlazor.Docs.Examples
<MudDialog DisableSidePadding="true">
<DialogContent>
<MudContainer Style="max-height: 300px; overflow-y: scroll">
@if (Loading)
{
<MudProgressCircular Indeterminate="true"></MudProgressCircular>
}
else
{
<MudText Style="white-space: pre-wrap;">@LicenseText</MudText>
}
</MudContainer>
</DialogContent>
<DialogActions>
<MudButton Color="Color.Primary" OnClick="Ok">Accept</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
[Inject] HttpClient HttpClient { get; set; }
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Loading = true;
var response = await HttpClient.GetAsync("https://raw.githubusercontent.com/Garderoben/MudBlazor/master/LICENSE");
LicenseText = await response.Content.ReadAsStringAsync();
Loading = false;
}
private string LicenseText;
private bool Loading = false;
private void Ok()
{
MudDialog.Close(DialogResult.Ok(true));
}
}
And the test which is auto generated just makes sure the example renders without error
[Test]
public void DialogScrollableExample_Test()
{
ctx.RenderComponent<DialogScrollableExample>();
}
Thanks for taking the time to report this. I am aware of the issue, and will be attempting to fix it in the next release.
@egil Is this the same as #319 ?
@egil Is this the same as #319 ?
Exactly.
@mikes-gh I just pushed a small change to how the WaitFor logic works, to work around potential race conditions/timing issue. If you want, you can try out the nightly that include the change by following this guide: https://github.com/egil/bUnit/discussions/209
@egil I dont use anyWaitFor
in my code. Would it still apply?
No, that's unlikely.
So will there be. a fix for the situation where an exception is presented in the test thread on a seemingly random basis. Only very occasionaly does the exception make it to the test thread. Or maybe this is expected if I dont use waitfor?
Or maybe this is expected if I dont use waitfor?
No, this should ideally show up no matter what in the test output. It is the plan to fix that in #319.
Describe the bug
Firstly this may not be a bug with bUnit. These are some observations and I would like some advice on how to log repro these issues. Since moving our library to net5.0 our test pipeline has started giving seemingly random failures. We almost exclusively do component testing using bUnit. I am really not sure where to start. Could it possibly be a timing bug with bUnit on Linux (the build server)? I am at a loss since it seems different test fail every time so finding a pattern is very hard as you can imagine. The below is just an example although it probably doesn't help much sorry. This test will pass normally and will almost certainly pass if I just re-run the pipeline.
Example: Testing this component:
With this test:
Results in this output:
Expected behavior: Passes (It does usually)
Version info:
Additional context: Passes nearly all of the time. This is just one of seeming random failures. All tests that have passed in the past many times. One Thing that has chnaged that seems to have triggered these random failures is our library moving to net 5.0
cc @henon