本文來安利大家一個支持使用中文做用例名的 WPF 界面 UI 單元測驗框架
賣點
有沒有覺得命名太難?有沒有覺得單元測驗的命名更難?沒錯,這是一個業界的大問題,很多團隊都會因為單元測驗的用例函式命名太難而讓團隊成員不喜歡寫單元測驗,或者說代碼審查的時候覺得對方寫的單元測驗用例名有語法錯誤,又或者是改到單元測驗時發現函式命名因為自己英文能力有限而看不懂
本文安利給大家的 dotnetCampus.UITest.WPF 單元測驗框架將用來解決此問題,使用它,你可以用契約的方式來描述一個又一個的測驗用例,這些測驗用例將在單元測驗運行結束后顯示到單元測驗控制臺或 GUI 視窗中,全程序你完全不需要為任何單元測驗方法進行命名——你關注的,是測驗用例本身
現在,你的單元測驗可以這樣寫了:
[TestClass]
public class DemoTest
{
[UIContractTestCase]
public void TestAsyncLoad()
{
"等待視窗顯示出來,可以成功進行異步等待,不會鎖主執行緒".Test(async () =>
{
var mainWindow = new MainWindow();
var taskCompletionSource = new TaskCompletionSource();
mainWindow.Loaded += (sender, args) => taskCompletionSource.SetResult();
await mainWindow.Dispatcher.InvokeAsync(mainWindow.Show);
await taskCompletionSource.Task;
});
}
}
于是,運行單元測驗將看到這樣的結果視圖:

本 UI 單元測驗框架,僅僅提供的是讓你可以使用 CUint(Chinese Unit Test) 風格撰寫 UI 測驗代碼,所有的放在 Test 內的代碼將會在 UI 執行緒執行,本 UI 單元測驗框架不提供面向測驗的輔助型別的方法,例如模擬滑鼠點擊等功能,如需這些功能,還請使用第三方的庫進行輔助
使用方法
此單元測驗框架是基于 MIT 最友好開源協議,在 GitHub 上完全開源的,請看 https://github.com/dotnet-campus/CUnit/
此單元測驗框架是 MSTest v2 的一個擴展,在使用時,你需要創建一個 MSTest 的單元測驗專案,在此單元測驗專案里面額外安裝 dotnetCampus.UITest.WPF 庫,對于在使用新 SDK 風格的 csproj 檔案,可以編輯加入如下代碼進行安裝庫
<PackageReference Include="dotnetCampus.UITest.WPF" Version="2.2.0" />
如果你的單元測驗專案里面包含了 WPF 的 App.xaml 檔案,為了修復構建單元測驗時有多個入口 Main 函式問題,你需要額外加入以下代碼用于修復此問題
<ItemGroup>
<ApplicationDefinition Remove="App.xaml" />
</ItemGroup>
<ItemGroup>
<Page Include="App.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
以上對 App.xaml 的修復非必須,只有你的單元測驗專案里面包含了 App.xaml 才有此需求,此問題不是 dotnetCampus.UITest.WPF 庫引入,而是通用的單元測驗就存在的問題,對于大部分的 UI 單元測驗專案來說,都不會也不應該包含 App.xaml 檔案,除非這是針對 WPF 的 UI 類別庫的單元測驗,對于應用本身的 UI 單元測驗來說,都應該傳入的是應用的 App 類
更改完成之后的 csproj 的內容大概如下
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>exe</OutputType>
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<ApplicationDefinition Remove="App.xaml" />
</ItemGroup>
<ItemGroup>
<Page Include="App.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
<PackageReference Include="coverlet.collector" Version="3.1.0" />
<PackageReference Include="dotnetCampus.UITest.WPF" Version="2.2.0" />
</ItemGroup>
</Project>
在開始撰寫實際的 UI 單元測驗之前,需要初始化 UI 測驗引擎,這是因為 WPF 需要給定指定的 App 入口函式,用于尋找程式集資源,代碼如下
[TestClass]
public class FooTest
{
[AssemblyInitialize]
public static void InitializeApplication(TestContext testContext)
{
UITestManager.InitializeApplication(() => new App());
}
}
在 WPF 里面,有資源程式集等概念,通過以上代碼初始化引擎即可自動完成設定,在一個公開的標記了 TestClassAttribute 特性的測驗型別里面,存放一個靜態的,標記了 AssemblyInitializeAttribute 特性的帶有 TestContext 引數的方法,將會在開始單元測驗之前被執行,在此函式里面,需要呼叫 UITestManager 初始化引擎,將自己測驗的專案里的 WPF 應用入口的 App 類傳入
接下來即可開始撰寫業務上的單元測驗代碼,如以下例子
[TestClass]
public class FooTest
{
[AssemblyInitialize]
public static void InitializeApplication(TestContext testContext)
{
UITestManager.InitializeApplication(() => new App());
}
[UIContractTestCase]
public void TestAsyncLoad()
{
"等待視窗顯示出來,可以成功進行異步等待,不會鎖主執行緒".Test(async () =>
{
var mainWindow = new MainWindow();
var taskCompletionSource = new TaskCompletionSource();
mainWindow.Loaded += (sender, args) => taskCompletionSource.SetResult();
await mainWindow.Dispatcher.InvokeAsync(mainWindow.Show);
await taskCompletionSource.Task;
});
}
[UIContractTestCase]
public void TestMainWindow()
{
"打開 MainWindow 視窗,可以成功打開視窗".Test(() =>
{
Assert.AreEqual(Application.Current.Dispatcher, Dispatcher.CurrentDispatcher);
var mainWindow = new MainWindow();
bool isMainWindowLoaded = false;
mainWindow.Loaded += (sender, args) => isMainWindowLoaded = true;
mainWindow.Show();
Assert.AreEqual(true, isMainWindowLoaded);
});
"關閉 MainWindow 視窗,可以成功關閉視窗和收到視窗關閉事件".Test(() =>
{
var window = Application.Current.MainWindow;
Assert.AreEqual(true, window is MainWindow);
bool isMainWindowClosed = false;
Assert.IsNotNull(window);
window.Closed += (sender, args) => isMainWindowClosed = true;
window.Close();
Assert.AreEqual(true, isMainWindowClosed);
});
}
}
每個進入的函式都是在 UI 執行緒執行的,可以放心呼叫任何的 UI 資源
代碼
本文所有代碼放在github 和 gitee 歡迎訪問
可以通過如下方式獲取本文的源代碼,先創建一個空檔案夾,接著使用命令列 cd 命令進入此空檔案夾,在命令列里面輸入以下代碼,即可獲取到本文的代碼
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 5d83d18e3f369c36759e1b3d1b6afc1a1c3cac30
以上使用的是 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
獲取代碼之后,進入 dotnetCampus.UITest.WPF.Demo 檔案夾
博客園博客只做備份,博客發布就不再更新,如果想看最新博客,請到 https://blog.lindexi.com/

本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可,歡迎轉載、使用、重新發布,但務必保留文章署名[林德熙](http://blog.csdn.net/lindexi_gd)(包含鏈接:http://blog.csdn.net/lindexi_gd ),不得用于商業目的,基于本文修改后的作品務必以相同的許可發布,如有任何疑問,請與我[聯系](mailto:[email protected]),
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/412766.html
標籤:WPF
