本文来安利大家一个支持使用中文做用例名的 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 资源

代码

本文所有代码放在githubgitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 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 文件夹

dotnetCampus.UITest.WPF 一个支持中文用例的界面单元测试框架的更多相关文章

  1. 使用Swing组件编写一个支持中文文本编辑程序ChineseTextEdit.java

      import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.io.*; public class C ...

  2. 使用react-native做一个简单的应用-04界面主框架

    欢迎界面搭建完毕,我们接下来需要做的就是搭建应用程序的主体框架啦.首先我们看一下首页的截图: 从图中看到,我将首页分为了三部分:用黑色矩形表示的头部,绿色表示的内容和红色表示的底部. 下面我们需要解决 ...

  3. netty系列之:轻轻松松搭个支持中文的服务器

    目录 简介 netty的HTTP支持 netty中使用HTTP的原理 100 (Continue) Status 为netty搭建HTTP服务器 总结 简介 之前讲了那么多关于netty的文章,都是讲 ...

  4. JS导出PDF插件(支持中文、图片使用路径)

    在WEB上想做一个导出PDF的功能,发现jsPDF比较多人推荐,遗憾的是不支持中文,最后找到pdfmake,很好地解决了此问题.它的效果可以先到http://pdfmake.org/playgroun ...

  5. QT 4.7支持中文(QT4.7)(中文)(makeqpf)

    QT 4.7支持中文(QT4.7)(中文)(makeqpf) 摘要: QT4.7.0在移植到开发板上的时候,中文支持是必不可少的,如何让QT支持中文,如何制作QT支持的字体文件,如何使QT UI编辑器 ...

  6. IOS Android支持中文与本地文件的读取写入

    转自http://www.xuanyusong.com/archives/1069 和http://www.benmutou.com/archives/2094 前几天有个朋友问我为什么在IOS平台中 ...

  7. 美化你的GRUB,全面支持中文(菜单、提示、帮助)适用7.04-9.04

    本文根据网络资料整理而成,在此鸣谢各位作者. 本方法适合 7.04-9.04版本,9.10使用了grub2,请看这里. http://forum.ubuntu.org.cn/viewtopic.php ...

  8. Unity3D研究院之IOS Android支持中文与本地文件的读取写

       前几天有个朋友问我为什么在IOS平台中可以正常的读写文件可是在Android平台中就无法正常的读写.当时因为在上班所以我没时间来帮他解决,晚上回家后我就拿起安卓手机真机调试很快就定位问题所在,原 ...

  9. PHP生成PDF完美支持中文,解决TCPDF乱码

    PHP生成PDF完美支持中文,解决TCPDF乱码 2011-09-26 09:04 418人阅读 评论(0) 收藏 举报 phpfontsheaderttfxhtml文档 PHP生成PDF完美支持中文 ...

  10. 使用CEF(二)— 基于VS2019编写一个简单CEF样例

    使用CEF(二)- 基于VS2019编写一个简单CEF样例 在这一节中,本人将会在Windows下使用VS2019创建一个空白的C++Windows Desktop Application项目,逐步进 ...

随机推荐

  1. 记录--五个有用的iframe踩坑问题,快收藏!

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 你不会还不知道iframe不能嵌入百度首页吧?为了丰富用户体验,我们常常会将其他网站的内容嵌入到自己的网页中.然而,随之而来的是一个常见的 ...

  2. 记录--新的HTML标签 :<search>

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 本文介绍了一种新的HTML元素搜索方法,并提供了一个实用的工具来帮助开发者快速找到所需的元素.这对于那些需要处理大量HTML元素的开发者来 ...

  3. 记录-有意思的气泡 Loading 效果

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 今日,群友提问,如何实现这么一个 Loading 效果: 这个确实有点意思,但是这是 CSS 能够完成的? 没错,这个效果中的核心气泡效果 ...

  4. VScode 配置私钥免密登录

    VScode 配置私钥免密登录 配置公钥私钥进行免密登录在前文已经提及.在完成上述配置后,我们希望在VScode中配置,毕竟主要的开发环境还是在VScode上且连接到远程服务器会经常遇到网络不稳定需要 ...

  5. 无监督学习-K-means算法

    无监督学习-K-means算法 1. 什么是无监督学习 一家广告平台需要根据相似的人口学特征和购买习惯将美国人口分成不同的小组,以便广告客户可以通过有关联的广告接触到他们的目标客户. Airbnb 需 ...

  6. C++设计模式 - 代理模式(Proxy)

    接口隔离模式 在组件构建过程中,某些接口之间直接的依赖常常会带来很多问题.甚至根本无法实现.采用添加一层间接(稳定)接口,来隔离本来互相紧密关联的接口是一种常见的解决方案. 典型模式 Facade P ...

  7. #轮廓线dp#HDU 1400 Mondriaan's Dream

    题目传送门 分析 状压dp会TLE,考虑用轮廓线dp, 设 \(dp[i][j][S]\) 表示现在处理到 \((i,j)\) 这个位置轮廓线上状态为 \(S\) 的情况 二进制位为1表示左边或者上方 ...

  8. 使用 rollup 打包可按需加载的 NPM 包

    安装 rollup npm install rollup --save-dev 配置文件 rollup.config.js export default { input: 'src/index.js' ...

  9. OpenHarmony组件复用示例

      本文转载自<#2023盲盒+码# OpenHarmony组件复用示例>,作者zhushangyuan_ ● 摘要:在开发应用时,有些场景下的自定义组件具有相同的组件布局结构,仅有状态变 ...

  10. WPF/MVVM模式入门教程(二):实现INotifyPropertyChanged接口

    引用:https://www.cnblogs.com/flh1/p/12447188.html 1.创建NotifyPropertyChanged类 我们在common文件夹下创建一个名为Notify ...