[Test] publicvoidRenderWithoutResponse() { usingvar ctx = new Bunit.TestContext();
var comp = ctx.RenderComponent<FetchData>(); Console.WriteLine(comp.Markup); }
應該會看到測試失敗,原因就是在 init 時有使用到 HttpClient。
This test requires a HttpClient to be supplied, because the component under test invokes the HttpClient during the test. The request that was sent is contained within the ‘Request’ attribute of this exception. Guidance on mocking the HttpClient is available on bUnit’s website.
using System; using System.Net; using System.Net.Http; using System.Net.Http.Headers; using System.Text.Json; using Bunit; using Microsoft.Extensions.DependencyInjection; using RichardSzalay.MockHttp;
namespacetest;
publicstaticclassMockHttpClientBunitHelpers { publicstatic MockHttpMessageHandler AddMockHttpClient(this TestServiceProvider services) { var mockHttpHandler = new MockHttpMessageHandler(); var httpClient = mockHttpHandler.ToHttpClient(); httpClient.BaseAddress = new Uri("http://localhost"); services.AddSingleton<HttpClient>(httpClient); return mockHttpHandler; }
publicstatic MockedRequest RespondJson<T>(this MockedRequest request, T content) { request.Respond(req => { var response = new HttpResponseMessage(HttpStatusCode.OK); response.Content = new StringContent(JsonSerializer.Serialize(content)); response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); return response; }); return request; }
publicstatic MockedRequest RespondJson<T>(this MockedRequest request, Func<T> contentProvider) { request.Respond(req => { var response = new HttpResponseMessage(HttpStatusCode.OK); response.Content = new StringContent(JsonSerializer.Serialize(contentProvider())); response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); return response; }); return request; } }
接著來修改剛剛的測試案例,在 Service 註冊 HttpClient 就可以讓測試順利通過,並且看到結果包含著 Loading… 的字串。
1 2 3 4 5 6 7 8 9
[Test] publicvoidRenderWithoutResponse() { usingvar ctx = new Bunit.TestContext(); var mock = ctx.Services.AddMockHttpClient();
var comp = ctx.RenderComponent<FetchData>(); StringAssert.Contains("Loading...", comp.Markup); }
mock API
使用 mock 物件提供的 When 以及剛剛所寫的 RespondJson 方法,來處理資料。
1 2 3 4 5 6 7 8 9 10 11 12 13
[Test] publicvoidRenderWithoutResponse() { usingvar ctx = new Bunit.TestContext(); var mock = ctx.Services.AddMockHttpClient(); mock.When("/sample-data/weather.json").RespondJson(new List<FetchData.WeatherForecast> { new() {Date = new DateTime(2022, 01, 20), TemperatureC = 15, Summary = "first data"} });
var comp = ctx.RenderComponent<FetchData>(); StringAssert.Contains("Loading...", comp.Markup); }
可以發現這樣怎麼還是沒重新 render 拿到新的 html 結構,因為是使用非同步的方法取得資料,因此測試也需要使用非同步的方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
[Test] publicvoidRenderMockResponse() { usingvar ctx = new Bunit.TestContext(); var mock = ctx.Services.AddMockHttpClient(); mock.When("/sample-data/weather.json").RespondJson(new List<FetchData.WeatherForecast> { new() {Date = new DateTime(2022, 01, 20), TemperatureC = 15, Summary = "first data"} });
var comp = ctx.RenderComponent<FetchData>(); comp.WaitForAssertion(() => { Assert.IsNotNull(comp.Find(".table")); }); }