前言 在AspnetCore生態系統中,我們測試項目一般使用Microsoft.AspNetCore.TestHost的TestServer 到.NET6後提供的Microsoft.AspNetCore.Mvc.Testing的WebApplicationFactory,後者是前者的封裝,專門用於測 ...
前言
在AspnetCore生態系統中,我們測試項目一般使用Microsoft.AspNetCore.TestHost
的TestServer
到.NET6後提供的Microsoft.AspNetCore.Mvc.Testing
的WebApplicationFactory
,後者是前者的封裝,專門用於測試 ASP.NET Core 應用程式。它簡化了創建和配置測試伺服器的過程。而Alba
也是基於前者的封裝,同樣提供了一些好用的測試體驗
使用 Alba 進行集成測試
以下我們來體驗一下TA的一些好用的測試體驗:
首先,你需要在項目中安裝 Alba 包。可以使用以下命令通過 NuGet 包管理器進行安裝:
dotnet add package Alba
為了演示 Alba 的使用,我們首先創建一個簡單的 ASP.NET Core 應用程式。這個應用程式包含一個返回 "Hello, World!" 的 MinimalApi請求。
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello, World!");
app.Run();
namespace TestCase
{
public partial class Program { } //定義一個入口點用於測試
}
接下來,我們使用 Alba 創建一個基於xUnit
的集成測試,測試上述應用程式。
using Alba;
public class IntegrationTests
{
[Fact]
public async Task Get_Home_Returns_HelloWorld()
{
using var host = await AlbaHost.For<TestCase.Program>(builder =>
{
// 這裡可以配置服務和中間件
});
await host.Scenario(scenario =>
{
scenario.Get.Url("/");
scenario.StatusCodeShouldBeOk();
scenario.ContentShouldBe("Hello, World!");
});
}
}
AlbaHost有一個方法Scenario(x=>{})
用於定義測試場景,比如上面的測試用例,場景使用GET請求起始頁並斷言是否返回200
,以及返回的文本是否是Hello, World!
對於內置場景沒有支撐到位的斷言,我們也可以使用參數接收IScenarioResult
自行斷言:
var myScenario = await _host.Scenario(_ =>
{
_.Get.Url("/");
});
Assert.Equal("true", myScenario.ReadAsText());
Assert.Equal(200, myScenario.Context.Response.StatusCode);
對於POST等方式提供鏈式的語法風格,Alba會自動幫我們序列化:
using Alba;
public class IntegrationTests
{
[Fact]
public async Task Post_Data_Returns_Correct_Response()
{
using var host = await AlbaHost.For<TestCase.Program>();
await host.Scenario(scenario =>
{
scenario.Post.Json(new { Name = "Test" }).ToUrl("/data");
scenario.StatusCodeShouldBeOk();
scenario.ContentShouldBe("Received: Test");
});
}
}
對於Xml
和FormData
的POST,Scenario
也是提供支持的,例如:
//xml
scenario.Post.Xml(new Input {Name = "vipwan", Age = 18});
//form
public async Task write_form_data(IAlbaHost system)
{
var form1 = new Dictionary<string, string>
{
["a"] = "what?",
["b"] = "now?",
["c"] = "really?"
};
await system.Scenario(_ =>
{
// This writes the dictionary values to the HTTP
// request as form data, and sets the content-length
// header as well as setting the content-type
// header to application/x-www-form-urlencoded
_.WriteFormData(form1);
});
}
當然除了傳參的時候自動序列化,Alba對響應的返回也提供了反序列化支持:
public async Task read_json(IAlbaHost host)
{
var result = await host.Scenario(_ =>
{
_.Get.Url("/output");
});
var output = result.ReadAsJsonAsync<Output>();
}
//或者
public async Task read_json_shorthand(IAlbaHost host)
{
var output = await host.GetAsJson<Output>("/output");
}
如果需要測試需要鑒權認證的請求,Alba也幫我們做了封裝.我們只需要實例化AuthenticationStub
或者JwtSecurityStub
亦或者實現OpenConnectExtension
,然後在實例化AlbaHost時傳入即可!
var securityStub = new AuthenticationStub()
.With("foo", "bar")//演示添加的claim
.With(JwtRegisteredClaimNames.Email, "[email protected]")//演示添加的claim
.WithName("vipwan");
myHost = await AlbaHost.For<WebAppSecuredWithJwt.Program>(securityStub);
如上面的代碼只要我們使用myHost
實例創建的任何場景將自動附加相應的認證信息:
//當請求需要認證的時候也可以通過測試
app.MapGet("/", () => "Hello, World!").RequireAuthorization();
對於請求Alba還支持請求的AOP,比如請求前後我們需要對HttpContext
做一些改動:
public void sample_usage(AlbaHost system)
{
// Synchronously
system.BeforeEach(context =>
{
// Modify the HttpContext immediately before each
// Scenario()/HTTP request is executed
context.Request.Headers.Add("trace", "something");
});
system.AfterEach(context =>
{
// perform an action immediately after the scenario/HTTP request
// is executed
});
// Asynchronously
system.BeforeEachAsync(context =>
{
// do something asynchronous here
return Task.CompletedTask;
});
system.AfterEachAsync(context =>
{
// do something asynchronous here
return Task.CompletedTask;
});
}
這裡介紹了一些Alba的特性和使用方式,當然還不完善,如果你對這個庫感興趣可以點擊鏈接查看官方的文檔
總結
Alba 是一個比較簡單的測試庫,提供了我們對Web項目測試常用的場景封裝,下圖是AlbaHost
簡單架構:
Alba 提供了多種便捷的測試方式,使得編寫和執行集成測試變得更加簡單和高效。無論是基本的 HTTP 請求測試、帶有依賴註入的請求測試、POST 請求測試、帶有認證的請求測試,還是複雜的請求和響應測試,Alba 都能很好地滿足你的需求。通過使用 Alba,你可以更輕鬆地編寫可靠的集成測試,確保你的應用程式在各種情況下都能正常工作。