VisualStudio中的单元测试
1. VisualStuio中的测试资源管理器、CodeLens和ReSharper
上一篇文章重温了《单元测试的艺术》里提到的单元测试的技术及原则。这篇文章实践使用VisualStudio 2019进行单元测试。
在VisualStudio中通常都会使用“测试资源管理器”进行单元测试。

Professional和Enterprise版本可以使用CodeLens,这大大方便了测试的运行与调试。

但CodeLens的图标常常刷不出来,一些第三方插件(如ReSharper)会更好用。
2. Live Unit Test
VisualStudio可以使用Live Unit Test(实时单元测试),这个功能需要Enterprise版本。

Live Unit Testing 是 Visual Studio 2017 中引入的一种技术。 进行代码更改时,它会自动执行单元测试。
实时单元测试:
让你更有信心地对代码进行重构和更改。 Live Unit Testing 在编辑代码时自动执行所有受影响的测试,确保所做更改不会中断测试。
指示单元测试是否充分覆盖代码,并显示未被单元测试覆盖的代码。 Live Unit Testing 以图形方式实时描绘代码覆盖率,以便一眼就能看到每行代码覆盖的测试数,目和未被任何单元测试覆盖的行。
Live Unit Testing是个很好的功能,唯一的障碍是,如果解决方案中包含了集成测试会导致Live Unit Testing响应变慢。解决方案是创建一个不包含集成测试项目的解决方案,或者在解决方案资源管理器中右键单击想要排除的每个测试项目,然后依次选择“实时测试” > “排除”,这样Live Unit Test就不会对这些项目进行测试。

3. 代码覆盖率
还是Enterprise版本的功能,Visual Studio的代码覆盖率工具可以很直观地查看到单元测试的代码覆盖率。

4. Microsoft Fakes
微软有他自己的隔离框架Microsoft Fakes(在公司名称后面加Fakes,这命名真是超烂)。不过Fakes不怎么建议使用。
Fakes有两种风格:
Stub(存根) 将类替换为可实现同一接口的小型替代项。
Shim(填充码) 在运行时修改应用的编译代码,这样就可以运行测试提供的垫片代码,而不用执行指定的方法调用。 填充码可用于替换对无法修改的程序集(如 .NET 程序集)的调用。
一般原则是,为在 Visual Studio 解决方案中进行的调用使用存根,并为对其他引用的程序集的调用使用填充码。 这是因为在你自己的解决方案中,通过按照存根要求的方式定义接口来分离组件是一个很好的做法。 但是,外部程序集(如 System.dll)通常没有单独的接口定义,因此必须改用填充码。
其他需要注意的事项还有:
性能。 填充码运行较慢,因为它们在运行时会重新编写你的代码。 存根没有这项性能开销,与虚方法运行的速度一样快。
静态方法和密封类型方法。 你只能使用存根实现接口。 因此,存根类型不能用于静态方法、非虚方法、密封虚方法、密封类型中的方法,等等。
内部类型。 存根和填充码都可用于可通过程序集特性 InternalsVisibleToAttribute 访问的内部类型。
私有方法。 如果方法签名中的所有类型都是可见的,则填充码可替换对私有方法的调用。 存根只能替换可见方法。
接口和抽象方法。 存根提供了可用于测试的接口和抽象方法的实现。 填充码无法检测接口和抽象方法,因为它们没有方法体。
但是由于不建议使用Fakes,所以基本上都会用NSub创建伪对象,Fakes的价值在于Shim,它有些别的隔离框架没有的独特功能。
下面已LogAn项目为例讲解Fakes的用法。首先在单元测试的引用列表右键选中LogAn项目,选择“添加 Fakes 程序集”,然后重新生成方案,这时候可见到项目中多了LogAn.Fakes的引用,以及多了一些Fakes的文件。

使用Stub的单元测试代码如下:
ICalculator calculator = new Fakes.StubICalculator
{
AddInt32Int32 = (arg1, arg2) => 3
};
Assert.AreEqual(calculator.Add(1, 2), 3);
重温一下NSub的相同功能:
_calculator = Substitute.For<ICalculator>();
_calculator.Add(1, 2).Returns(3);
Assert.AreEqual(_calculator.Add(1, 2), 3);
和NSub不同,Fakes提供的功能少了很多,不仅如此,每次更改项目都可能要重新添加Fakes引用(至少我在编译服务器上的项目老是因为Fakes出错)。所以一般不建议使用Fakes做Stub的功能。但是官方文档中外部程序集(如 System.dll)通常没有单独的接口定义,因此必须改用填充码 这句话却没有错,反正System.dll之类的第三方程序集又不可能经常改变,所以也没有需要重新添加Fakes程序集这个烦恼。下面介绍一下Shim的使用。
假设有一个类:
public static class Y2KChecker
{
public static void Check()
{
if (DateTime.Now == new DateTime(2000, 1, 1))
throw new ApplicationException("y2kbug!");
}
}
由于它依赖于DateTime.Now,而假设我们没办法更改这段代码,为了对它进行单元测试我们必须使用Shim破除对DateTime.Now的依赖。首先选中System引用并右键选择添加Fake程序集,然后在测试代码的ShimsContext中插入Shim:
using (ShimsContext.Create())
{
// Arrange:
System.Fakes.ShimDateTime.NowGet = () => new DateTime(2000, 1, 1);
// Act and Assert::
Assert.ThrowsException<ApplicationException>(Y2KChecker.Check);
}
如上面代码所示,Shim可以伪造DateTime.Now的值,这对单元测试提供了极大的方便。
5. 结语
虽然Fakes中的Stub不好用,但Shim还是挺有趣的,我建可以同时使用NSub和Fakes里的Shim。善用VisualStudio的各种工具可以大大提升单元测试的效率,不过基本上这些工具都只在Enterprise版本中提供。
有趣的是MSTest自己也没有用Fakes,很多时候都是用moq。(例如PlatformServiceProviderTests.cs)

另外VisualStudio还有一些有趣的工具辅助单元测试,例如walterlv的这篇博客(不再为命名而苦恼!使用 MSTestEnhancer 单元测试扩展,写契约就够了)介绍了一种更直观的单元测试编写方式,不放试一试:

6. 参考
测试工具 - Visual Studio Microsoft Docs
单元测试 - Visual Studio Microsoft Docs
用 Microsoft Fakes 隔离测试代码 - Visual Studio Microsoft Docs
了解如何使用实时单元测试测试代码 - Visual Studio Microsoft Docs
代码覆盖率测试 - Visual Studio Microsoft Docs
VisualStudio中的单元测试的更多相关文章
- 【Unity游戏开发】浅谈Unity游戏开发中的单元测试
一.单元测试的定义与作用 单元测试定义:单元测试在传统软件开发中是非常重要的工具,它是指对软件中的最小可测试单元进行检查和验证,一般情况下就是对代码中的一个函数去进行验证,检查它的正确性.一个单元测试 ...
- 好代码是管出来的——.Net Core中的单元测试与代码覆盖率
测试对于软件来说,是保证其质量的一个重要过程,而测试又分为很多种,单元测试.集成测试.系统测试.压力测试等等,不同的测试的测试粒度和测试目标也不同,如单元测试关注每一行代码,集成测试关注的是多个模块是 ...
- .NET 项目中的单元测试
.NET 项目中的单元测试 Intro "不会写单元测试的程序员不是合格的程序员,不写单元测试的程序员不是优秀的工程师." -- 一只想要成为一个优秀程序员的渣逼程序猿. 那么问题 ...
- 使用GIT进行源码管理 —— 在VisualStudio中使用GIT
GIT作为源码管理的方式现在是越来越流行了,在VisualStudio 2012中,就通过插件的现实对GIT进行了官方支持,并且这个插件在VS2013中已经转正.本文在这里简单的介绍一下如何在Visu ...
- Visual Studio中UnitTesting单元测试模板代码生成
在软件研发过程中,单元测试的重要性直接影响软件质量.经验表明一个尽责的单元测试方法将会在软件开发的某个阶段发现很多的Bug,并且修改它们的成本也很低.在软件开发的后期阶段,Bug的发 ...
- 真正意义上的spring环境中的单元测试方案spring-test与mokito完美结合
真正意义上的spring环境中的单元测试方案spring-test与mokito完美结合 博客分类: java 测试 单元测试SpringCC++C# 一.要解决的问题: spring环境中 ...
- 在Android中进行单元测试遇到的问题
问题1.Cannot connect to VM socket closed 在使用JUnit进行测试的时候,遇到这个问题.网上的解释是:使用Eclipse对Java代码进行调试,无论是远程JVM还 ...
- 在VisualStudio中应该使用什么字体
转自:http://blog.csdn.net/bclz_vs/article/details/6607695 字体通常分为几个主要类型 San-Serif:无衬线字体 Serif:有衬线的字体 Mo ...
- 在Android Studio中进行单元测试和UI测试
本篇教程翻译自Google I/O 2015中关于测试的codelab,掌握科学上网的同学请点击这里阅读:Unit and UI Testing in Android Studio.能力有限,如有翻译 ...
随机推荐
- python学习之路--python基础之列表操作
本文主要介绍下python列表的的一些基本操作 列表是我们在python编程中常用的数据类型之一,通过列表我们可以对数据实现最方便的存储.修改等操作. 定义列表 names=['ZhangSan',' ...
- 【安装】Hadoop2.8.0搭建过程整理版
Hadoop搭建过程 前期环境搭建主要分为软件的安装与配置文件的配置,集成的东西越多,配置项也就越复杂. Hadoop集成了一个动物园,所以配置项也比较多,且每个版本之间会有少许差异. 安装的方式有很 ...
- javascript函数详解
//函数的两种声明方式 //在同一个<script>标签中,函数的调用和声明位置可以没有先后的顺序,因为在同一个标签中,都是等加载到内存中,然后在运行 //但是如果是在两个script标枪 ...
- 你所不知的spring与mybatis整合方法
内容目录 1.采用MapperScannerConfigurer2.采用接口org.apache.ibatis.session.SqlSession的实现类org.mybatis.spring.Sql ...
- TensorFlow 2.0 入门教程实战案例
中文文档 TensorFlow 2 / 2.0 中文文档 知乎专栏 欢迎关注知乎专栏 https://zhuanlan.zhihu.com/geektutu 一.实战教程之强化学习 TensorFlo ...
- 洛谷P1003 铺地毯 noip2011提高组day1T1
洛谷P1003 铺地毯 noip2011提高组day1T1 洛谷原题 题目描述 为了准备一个独特的颁奖典礼,组织者在会场的一片矩形区域(可看做是平面直角坐标系的第一象限)铺上一些矩形地毯.一共有 n ...
- Spring MVC源码(一) ----- 启动过程与组件初始化
SpringMVC作为MVC框架近年来被广泛地使用,其与Mybatis和Spring的组合,也成为许多公司开发web的套装.SpringMVC继承了Spring的优点,对业务代码的非侵入性,配置的便捷 ...
- 使用flink Table &Sql api来构建批量和流式应用(2)Table API概述
从flink的官方文档,我们知道flink的编程模型分为四层,sql层是最高层的api,Table api是中间层,DataStream/DataSet Api 是核心,stateful Stream ...
- 神经大条的我-->记录我那些容易忘记的知识点
1.springmvc中每次进来的request都是保存在ThreadLocal里的,所以不会存在线程问题.可以直接用@Autowired全局注入 参考地址:https://my.oschina.n ...
- 最好的导航分割栏,分割线,实现底部透明,纯css
<div class="Ui_Ct_Line padding_5"> <div>为您推荐</div> </div> .Ui_Ct_L ...