在寫 asp dotnet core 時,如果沒有單元測試保證,需要每個方法都從 web api 的入口開始運行,此時的執行效率是很低的。而如果寫單元測試,又有一個坑的問題是寫單元測試也是需要時間的。本文告訴大家一些提高效率的方法,這些方法不是正經的用法,但是能提升效率。至於能不能用好不好用就請觀衆老爺自己決定
CUnit 中文命名單元測試
在寫單元測試時,小夥伴說需要讓單元測試的方法名符合 條件_執行_結果
而要求這個方法命名爲英文,我的英文就超級渣,這一點 少珺 小夥伴可以幫我證明。於是你會看到我寫了以下的測試 WhenABuDengYuThree_DokanarkelawNinirahajairi_SetSlj
的命名,而如果要我優化這個單元測試的命名,大家都知道,有些小夥伴和我一樣想一個好的命名可能佔了開發的一半時間
寫單元測試時,大量的單元測試方法命名將會佔用大量的時間,讓小夥伴不願意寫單元測試。或者寫出來的單元測試的只有自己能讀懂
在一個團隊裏面的,如果英文水平參差不齊,如我所在的團隊有英文特別厲害的walterlv和天龍也有英文特別差國語也特別差的大壯哥,還有英文有毒的本渣。此時用英文命名的單元測試就是一個神坑,除非團隊能成立一個改名部專門協助命名
一個解決方法是乾脆用中文命名單元測試算了,請看下面單元測試
[TestClass]
public class DemoTest
{
[ContractTestCase]
public void Foo()
{
"當滿足 A 條件時,應該發生 A' 事。".Test(() =>
{
// Arrange
// Action
// Assert
});
"當滿足 B 條件時,應該發生 B' 事。".Test(() =>
{
// Arrange
// Action
// Assert
});
}
}
運行單元測試將看到這樣的結果視圖
只要有任何一個單元測試炸了,相信小夥伴看提示特別快就知道哪裏炸了
使用這個庫的前提是用 NuGet 安裝 MSTestEnhancer 庫,如果是 SDK 格式的項目文件,可以添加下面代碼
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="Moq" Version="4.13.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.0.0" />
<PackageReference Include="MSTest.TestFramework" Version="2.0.0" />
<PackageReference Include="coverlet.collector" Version="1.0.1" />
<PackageReference Include="MSTestEnhancer" Version="1.6.0" />
</ItemGroup>
注意版本號需要你自己更新
在單元測試的方法裏面,推薦寫某個需要測試的方法,在方法上面添加特性 ContractTestCase
請看代碼
[ContractTestCase]
public void Foo()
接下來在方法裏面用一段字符串和 .Test
寫出對應的單元測試
"當滿足 A 條件時,應該發生 A' 事。".Test(() =>
{
// Arrange
// Action
// Assert
});
一個例子是我在DotNetGitLabWebHook用到的方法,代碼請看 github 是不是覺得寫起來特別快
用 CUnit(MSTestEnhancer) 能讓團隊內小夥伴寫單元測試的效率提升,也能提升團隊裏面讀單元測試以及單元測試炸瞭解決的效率
現在問題只有一個,你的團隊內對中文的看法是如何?千萬不要在我的博客下評論,我的博客的評論做的很渣,如果有很多人都在評論我的博客就用不了
利用原有依賴注入
在 asp dotnet core 的各個類可以在構造函數添加依賴注入的方法,如我的DotNetGitLabWebHook就在各個類裏面的構造函數添加了依賴注入
在 asp dotnet core 默認的構造函數依賴注入非常好用,例如我的 GitLabMRCheckerFlow.cs 用到兩個類 Notify 和 FileChecker 類,而 Notify 用到了 IConfiguration 配置,於是我可以這樣寫
public class Notify
{
/// <inheritdoc />
public Notify(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// 忽略代碼
}
// GitLabMRCheckerFlow.cs
public GitLabMRCheckerFlow(Notify notify, FileChecker fileChecker)
在 Startup.cs 的 ConfigureServices 添加註入
services.AddScoped<GitLabMRCheckerFlow>();
services.AddScoped<Notify>();
services.AddScoped<FileChecker>();
代碼請看 Startup.cs
此時獲取對象的方法都是放在構造函數參數,此時各個參數對應的類的創建也會自動注入構造參數。如在 GitLabMRCheckerFlow 需要傳入 Notify 參數,而創建 Notify 類需要傳入 IConfiguration 參數,這些都會在自帶的依賴注入完成
在寫 Controller 的單元測試時,難道我是需要運行一個 ASP.NET Core 服務,然後用 postman 進行測試?這樣的效率太低了,可以嘗試直接創建類調用對應的方法。而如果需要每個類都自己創建,這個創建效率實在太低,因爲創建一個類需要在他的構造函數傳入其他類,而這個類的構造函數可能後續修改,這樣的單元測試小夥伴都想砍人
簡單的方法是在單元測試創建服務
var hostBuilder = Program.CreateHostBuilder(new string[0]);
var build = hostBuilder.Build();
var serviceProvider = build.Services;
上面的代碼在單元測試裏面調用,調用上面代碼將會創建服務
然後拿到 serviceProvider 創建對象。如我需要測試 GitLabWebHookController 我可以給他的構造函數每個參數都在 serviceProvider 獲取,此時就不需要手動創建
public void MergeRequestTest()
{
var hostBuilder = Program.CreateHostBuilder(new string[0]);
var build = hostBuilder.Build();
var serviceProvider = build.Services;
using (var scope = serviceProvider.CreateScope())
{
var gitLabMrCheckerFlow = scope.ServiceProvider.GetService<GitLabMRCheckerFlow>();
var gitLabWebHookController = new GitLabWebHookController(gitLabMrCheckerFlow);
gitLabWebHookController.MergeRequest(TestMRJson.GetObject());
}
}
這裏有細節是 Controller 的注入有很多參數都是在 Scope 需要創建
而如果我的 Controller 有某些參數需要使用 Fake 或 Mock 的,這些參數就自己用 Mock 啦
通過這個方法會降低單元測試運行速度,但是能提升寫單元測試的效率
我搭建了自己的博客 https://blog.lindexi.com/ 歡迎大家訪問,裏面有很多新的博客。只有在我看到博客寫成熟之後纔會放在csdn或博客園,但是一旦發佈了就不再更新
如果在博客看到有任何不懂的,歡迎交流,我搭建了 dotnet 職業技術學院 歡迎大家加入
如有不方便在博客評論的問題,可以加我 QQ 2844808902 交流
本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名林德熙(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我聯繫。