ITPub博客

首页 > 人工智能 > 机器学习 > Visual Studio 2017高级编程(第7版)

Visual Studio 2017高级编程(第7版)

原创 机器学习 作者:qinghuawenkang 时间:2018-10-16 15:00:10 0 删除 编辑

Visual Studio 2017
高级编程
(第 7 版)
[ ] 布鲁斯·约翰逊( Bruce Johnson ) 著
李立新 译
北 京
Bruce Johnson
Professional Visual Studio 2017
EISBN: 978-1-119-40458-3
Copyright © 2018 by John Wiley & Sons, Inc., Indianapolis, Indiana
All Rights Reserved. This translation published under license.
Trademarks:
Wiley, the Wiley logo, Wrox, the Wrox logo, Programmer to Programmer, and related trade dress are
trademarks or registered trademarks of John Wiley & Sons, Inc. and/or its affiliates, in the United States and other countries,
and may not be used without written permission. Visual Studio is a registered trademark of Microsoft Corporation. All other
trademarks are the property of their respective owners. John Wiley & Sons, Inc., is not associated with any product or
vendor mentioned in this book.
本书中文简体字版由 Wiley Publishing, Inc. 授权清华大学出版社出版。未经出版者书面许可,不得以任何方式复制
或抄袭本书内容。
北京市版权局著作权合同登记号 图字: 01-2018-1001
Copies of this book sold without a Wiley sticker on the cover are unauthorized and illegal.
本书封面贴有 Wiley 公司防伪标签,无标签者不得销售。
版权所有,侵权必究。侵权举报电话: 010-62782989 13701121933
图书在版编目(CIP)数据
Visual Studio 2017 高级编程(第 7 版) / (美)布鲁斯·约翰逊(Bruce Johnson)著;李立新 译. —北京:清华大学出
版社, 2018
(.NET 开发经典名著)
书名原文: Professional Visual Studio 2017
ISBN 978-7-302-50633-1
Ⅰ. ①V… Ⅱ. ①布… ②李… Ⅲ. ①程序语言-程序设计 Ⅳ. ①TP312
中国版本图书馆 CIP 数据核字(2018)第 158340 号
责任编辑 :王 军 韩宏志
装帧设计 :孔祥峰
责任校对 :成凤进
责任印制 :李红英
出版发行: 清华大学出版社
网 址: http://www.tup.com.cn, http://www.wqbook.com
地 址: 北京清华大学学研大厦 A 座 邮 编: 100084
社 总 机: 010-62770175 邮 购: 010-62786544
投稿与读者服务: 010-62776969, c-service@tup.tsinghua.edu.cn

质量反馈: 010-62772015, zhiliang@tup.tsinghua.edu.cn
印 装 者 :清华大学印刷厂





:全国新华书店



190mm × 260mm 33.75 1217 千字


版 次 2018 8 月第 1 印 次 2018 8 月第 1 次印刷
定 价 99.80
——————————————————————————————————————————————
产品编号:
078953-01
译 者 序
Microsoft Visual Studio 是一个综合性产品, 适用于希望升级和创建精彩应用程序的组织、 团队和开发人员。 Microsoft
Visual Studio
包含大量有助于提高编程效率的新功能以及专用于跨平台开发的新工具, 如 UML 、 代码管控、 IDE 等。
Visual Studio 是目前最流行的程序集成开发环境之一,最新版本 Visual Studio 2017 基于 .NET Framework 4.5.2
Visual Studio 2017 的特点如下:
Code Snippet Editor : 这是一个第三方工具,用于在 Visual Basic 中创建代码片段。 Code Snippet Editor
具参见第
8 章。
灵活性: 生成面向所有平台的应用。
高效: 将设计器、编辑器、调试器和探查器集于一身。
完整的生态系统: 可访问数千个扩展,还可利用合作伙伴和社区提供的工具、控件和模板,对 Visual Studio
进行自定义和扩展。
兼容各种语言: 采用 C# Visual Basic F# C++ HTML JavaScript TypeScript Python 等进行编码。
轻型模块化安装: 全新安装程序可优化,确保只选择自己所需的模块。
功能强大的编码工具: 用各种语言轻松自如地编码,快速查找和修复代码问题,并轻松进行重构。
高级调试: 进行调试,快速找到并修复 bug 。用分析工具找到和诊断性能问题。
设备应用: 适用于 Apache Cordova Xamarin Unity 的工具。
Web 工具: 可使用 ASP.NET Node.js Python JavaScript 进行 Web 开发。可使用 AngularJS jQuery
Bootstrap Django Backbone.js 等功能强大的 Web 框架。
Git 集成: 在 GitHub 等提供商托管的 Git 存储库中管理源代码。也可使用 Visual Studio Team Services 管理
整个项目的代码、
bug 和工作项。
登录到
Visual Studio Community ,即可访问丰富的免费开发工具和资源。
本书内容丰富、概念清晰,采用以
IDE 为中心的新颖方法揭示 Visual Studio 2017 的诸多秘密,详细介绍 Visual
Studio 2017
的基础知识、编程方法及技巧,力求将最新、最全面、最实用的技术展现给读者,是开发新手和从早期
版本升级的开发人员必备的参考资料。
本书用通俗易懂的语言向读者介绍
Visual Studio 的功能,书中所涉及的代码及用例都是作者精心挑选的。每段代码
既有良好的可读性,又能很好地传达作者意图,使读者能轻松地理解每项功能,掌握
Visual Studio 的使用和开发秘诀!
本书分为集成开发环境、入门、进阶、桌面应用程序、
Web 应用程序、移动应用程序、云服务、数据、调试、
构建和部署、
Visual Studio 版本共 11 部分,列举大量实例论述如何将最现代的软件工程思想应用于软件开发生命
周期的各个阶段
( 需求、项目管理、架构设计、开发和测试等 ) 。本书大部分实例程序都可直接用于用户开发的应用
程序中。
最后,祝各位开发者在学习过程中一帆风顺,能熟练掌握使用
Visual Studio 开发的技巧,实现自己的编程梦想。
这里要感谢清华大学出版社的编辑,他们为本书的翻译付出了很多心血。没有他们的帮助和鼓励,本书不可能
顺利付梓。本书全部章节由李立新翻译,参与翻译的还有陈妍、何美英、陈宏波、熊晓磊、管兆昶、潘洪荣、曹汉
鸣、高娟妮、王燕、谢李君、李珍珍、王璐、王华健、柳松洋、曹晓松、陈彬、洪妍、刘芸、邱培强、高维杰、张
素英、颜灵佳、方峻、顾永湘、孔祥亮。
对于这本经典之作,译者本着“诚惶诚恐”的态度,在翻译过程中力求“信、达、雅”,但鉴于译者水平有限,
错误和失误在所难免,如有任何意见和建议,请不吝指正。
译者

作 者 简 介
Bruce Johnson ObjectSharp 咨询公司的一位合作伙伴,在计算机界具有 30 年的工作经验。他的前三个职业是
从事“具体工作”, 即在
UNIX 上编程。 但他在 20 年的时间内处理的项目所使用的都是 Windows 前沿技术, 从 C++
Visual Basic C# 、胖客户端应用程序、 Web 应用程序、 API 乃至各种数据库和前端开发。
除了喜欢建立系统之外,
Bruce 还在北美会议上和用户组中发言数百次。他是 Microsoft Certified Trainer(MCT)
.NET User Group Metro Toronto 的副组长。他还为许多杂志撰写专栏和文章。由于所有这些成就, Bruce 在过去
10 年中一直是 Microsoft MVP 。目前他在撰写新书。

技术编辑简介
John Mueller 是一名自由撰稿人和技术编辑。他醉心于写作,至今已经出版了 104 本书,发表了 600 多篇文章。
主题包括网络、人工智能、数据库管理、编程
( 入门到精通 ) 等。他目前的作品包括一本关于机器学习的书籍,几本
Python 书籍,还有一本关于 MATLAB 的书籍。他还编写了 AWS for Admins for Dummies AWS for Developers for
Dummies
,前者为管理员提供了开始使用 AWS 的入门书籍,后者适用于开发人员。他凭借技术编辑技巧帮助 70
位作者修改手稿。
John 一直对开发很感兴趣,他编写过介绍多种语言的图书,包括一本非常成功的 C++ 书籍。读者
可在
http://blog.johnmuellerbooks.com 上访问 John 的博客,也可通过 John@JohnMuellerBooks.com 联系 John

致 谢
在外行看来,写书似乎是个人的事。其实不然,甚至根本不是这样。没有多位人士为此付出的努力、提供的帮
助,本书就不可能出版。参与编写和编辑过程的其他人从来都没有得到足够的感谢。本书清晰、准确、有效,是因
为编辑、技术审核人员和责任编辑都付出了努力,还有负责出版、封面的人士,以及这里未提及的书中其他人士。
非常感谢这些人提供的帮助,也很高兴能与这些人一起工作。
由衷地感谢
Wrox 公司帮我完成本书的所有人,特别是 Kelly Talbot ,如果我没记错的话,这是我与 Kelly 合作
的第三本或第四本书。一如既往,他对细节的关注使本书避免了大量错误。不仅如此,他的耐心和勤奋确保我能按
时完成任务。也感谢
John Mueller ,他不仅确保我在第一稿中犯的技术错误在出版前都更正过来,而且提供了一些
很好的建议,帮助我理顺了内容。最后,多亏
Nancy Bell ,她阅读了我撰写的内容,保证其语法上的正确性。所
有这些人的努力终于促成了本书成功出版。

前 言
Visual Studio 作为开发工具,一直都在竞争中处于领先地位。负责开发 Visual Studio 的团队一直把编码效率列
在优先级列表的顶部。这个版本延续了这个传统。
Visual Studio 总是融合了 Microsoft 主要编程语言 (Visual Basic
C#) 的最新改进,还添加了一些小功能,这对程序员来说是件好事。但在更高层次上, Visual Studio 2017 将以多种
方式拥抱开源、移动开发和云计算。
Azure 不断推出新的功能和产品, Visual Studio 2017 将与它们无缝集成。理论
上,使用记事本和命令行窗口这样的简单工具也可以创建任意
.NET 应用程序,但开发人员一般不会这么做。 Visual
Studio 2017
包含了许多改进功能和新功能,以简化开发工作。
无论从哪方面看,
Visual Studio 2017 都是一款庞大的产品,所以初学者和经验丰富的 .NET 开发人员要找到需
要的功能比较困难。本书介绍这个开发工具的所有主要方面,阐述如何使用每项功能,给出如何高效使用各种组件
的建议,还说明
Visual Studio 2017 的组成部分,并把用户界面分解为容易管理的块以便于理解。此后详细描述这些
组件,包括它们各自的作用以及相互之间如何协调工作,并介绍未包含在该产品中的一些工具,使开发工作更高效。
本书读者对象
本书面向所有 Visual Studio 开发新手以及想学习一些新特性的有经验的编程人员。
熟悉
Visual Studio 编程环境的读者可跳过本书的第Ⅰ部分,该部分介绍用户界面的基本构造。安装过程变化最
大,粒度更细了,意味着你可以只安装所需的内容;如果不首先安装组件,安装过程只需要单击一两次即可完成。
增加的功能不多,因此可以不阅读第Ⅰ部分,但
Visual Studio 2017 中的一些变化可以使开发更高效;毕竟,这是读
者阅读本书的目的。
初次使用
Visual Studio 的读者,应该先阅读本书的第Ⅰ部分,该部分介绍了一些最基本的概念,为读者展示用
户界面,并讲解如何定制自己的编程环境。
本书主要内容
Visual Studio 2017 无疑是目前可供开发人员使用的最佳集成开发环境 (IDE) 。它基于成熟的编程语言和接口,受
到开发环境许多不同方面的影响。
Visual Studio 2017 不是一个革命性版本。然而,无论创建什么类型的应用程序,都要做一些调整——很小的调
( 例如 .NET Core) 。 熟悉这些变化可以帮助我们更好地完成工作。 出于这个原因, 以及为了更好地帮助 Visual Studio
新手,本书涵盖了该产品的所有内容。这样,读者会更熟悉界面,更得心应手。
Visual Studio 2017 有几个版本:社区版、专业版和企业版。本书主要介绍 Visual Studio 2017 的专业版,但有些
功能只在企业版中才有。如果之前没用过这些版本,请参阅第
38 章和第 39 章的相关内容。
本书组织结构
本书分为以下 11 个部分:
集成开发环境: 本书前 5 章旨在帮助你熟悉 Visual Studio 2017 的核心部分。从 IDE 结构和布局到各种选项
和设置,包含使用户界面匹配自己的工作方式所需的所有内容。
入门: 该部分介绍如何控制项目,以及如何组织它们,以符合自己的风格。
进阶: 虽然 Visual Studio 的许多图形组件使程序员的工作更容易完成,但程序员在编码时经常需要其他一些
帮助。因此,本部分介绍支持应用程序编码的功能,如
IntelliSense 、代码重构以及单元测试的创建和运行。
桌面应用程序: 在 .NET Framework 中,富客户 应用程序已经有了很大的变化,从 Windows Form 应用程
序到
Windows Presentation Foundation (WPF) ,再到通用 Windows 平台应用程序,每个应用程序都用单独的
一章来探讨。
Web 应用程序: Web 应用程序比桌面应用程序有更多的变化。就像桌面应用程序一样,三种不同的开发风
(ASP.NET Web 窗体、 ASP.NET MVC .NET Core) 都用单独的一章来探讨。几个新功能:块、 Node.js
Python 也包括在这一部分。
移动应用程序: Visual Studio 2017 支持用两种不同的风格来开发移动应用程序。通过 Xamarin ,可以使用熟
悉的
.NET 组件创建移动应用程序。通过 Apache Cordova( 以前的 PhoneGap) , 可以针对移动设备使用 HTML
CSS JavaScript
云服务: Visual Studio 2017 以各种方式支持云。 Windows Azure 这一章着眼于 Azure 的一些新特性如何集成
Visual Studio 中。此外,还研究如何使用同步服务作为数据存储平台,以及如何为 SharePoint 创建应用
程序。
数据: 大多数应用程序都使用某种数据存储形式。 Visual Studio 2017 .NET Framework 都包含处理数据库
和其他数据源的强大支持。本部分讲述如何使用
Visual Database Tools ADO.NET Entity Framework 构建
处理数据的应用程序,还讨论如何使用
Azure 中的几个新功能支持数据仓库的构建和数据分析。
调试: 应用程序调试是开发人员必须完成的一项较难任务,但正确使用 Visual Studio 2017 的调试功能有助
于分析应用程序的状态,并确定出错的原因。该部分介绍
IDE 提供的调试支持功能。
构建和部署: 除讨论如何构建有效的解决方案和向最终用户交付应用程序外,该部分还涉及如何升级以前
版本的项目。
Visual Studio 版本: 本书最后一部分介绍只能在 Visual Studio 2017 的企业版中使用的功能, 另外探讨 Visual
Studio Team Services
为管理软件项目提供的基本工具。
尽管对
Visual Studio 功能进行了上述分解,并提供了逻辑性最强、易于理解的主题,但读者仍需要查找特定的
功能来帮助自己完成某个活动。为了满足这个需求,只要在本书的其他地方详细介绍某个功能,本书就会提供对应
章节的参考。
随着
Visual Studio 的发展,本书的早期版本已经发展到了难以控制的地步。 Visual Studio 2017 还有更多功能,
为避免本书的篇幅超过
2000 页,我们从早期版本的 Visual Studio 中选取了一些章节,将它们放到一个在线档案中;
这些章节包含了
Visual Studio 2017 中没有更改或增强的特性。因此,一般来说,如果想在 Visual Studio 2017 中使
用这些指令,其中的说明将会适用。可以在
www.wrox.com 上找到这个在线档案。
本书使用前提
为高效地使用本书,需要安装 Visual Studio 2017 专业版,结合本书的内容安装软件并实际操作,会在极短时间
内掌握高效使用
Visual Studio 2017 的方法。为了跟随本书中的所有示例,应确保在 Visual Studio 2017 安装期间安
装以下工作负载
( 如第 1 章所述 )
● Universal Windows Platform
● .NET desktop development
● ASP.NET and web development
● Azure development
● Node.js development
● Data storage and processing
● Data science and analytical applications
● Mobile development with .NET
● Mobile development with Javascript
● .NET code cross-platform development
本书假设读者已经熟悉传统的编程模型,将使用 C# Visual Basic(VB) 语言演示 Visual Studio 2017 的功能。此
外,还假设读者能理解代码清单,因此不解释这两种语言的基本编程概念。如果读者刚开始编程,希望学习
Visual
Basic
,可以阅读 Bryan Newsome 编著的《 Visual Basic 2015 入门经典 ( 8 ) 》。同样,如果希望有一本关于 C#
好书,可以阅读
Benjamin Perkins Jacob Vibe Hammer Jon D. Reid 编著的《 C# 入门经典 ( 7 ) 》。
一些章节讨论了与 Visual Studio 一起使用的其他产品和工具,可以从网站下载免费版本或试用版本。
Code Snippet Editor : 这是一个第三方工具,用于在 Visual Basic 中创建代码片段。 Code Snippet Editor
具的详情请参见第
8 章。
SQL Server 2016 Visual Studio 2017 的安装包包含 SQL Server 2016 Express ,可构建使用数据库文件的应
用程序。但对于比较全面的企业解决方案而言,可使用
SQL Server 2016
Visual Studio 2017 企业版: 一个更强大的 Visual Studio 版本,针对开发过程中的其他阶段 ( 如测试和设计 )
引入了工具。有关内容请参见第 38 章和第 39 章。
Team Foundation Server Team Foundation Service : 这个服务器产品 ( 或基于云的产品 ) 提供了 Visual
Studio 2017
中的应用程序生命周期管理功能,参见第 40 章。
Windows 7 Windows 8 Windows 10 Visual Studio 2017 Windows 7 SP1 Windows 8.1 Windows 10
兼容,可以生成在 Windows XP Windows Vista Windows 7 Windows 8 Windows 10 上运行的应用程序。
勘误表
尽管我们已经尽了各种努力来保证书中不出现错误,但错误总是难免的,如果你在本书中找到了错误,例如拼
写错误或代码错误,请告诉我们,我们将非常感激。通过勘误表,可以让其他读者避免被误导,当然,这还有助于
提供更高质量的信息。
请给
wkservice@vip.163.com 发电子邮件,我们就会检查你的信息,如果是正确的,我们将在本书的后续版本
中采用。
要在网站上找到本书的勘误表,可以登录
http://www.wrox.com ,通过 Search 工具或书名列表查找本书,然后在
本书的细目页面上,单击
Book Errata 链接。在这个页面上可以查看到 Wrox 编辑已提交和粘贴的所有勘误项。完整
的图书列表还包括每本书的勘误表,网址是
www.wrox.com/misc-pages/booklist.shtml
p2p.wrox.com
要与作者和同行讨论,请加入 p2p.wrox.com 上的 P2P 论坛。这个论坛是一个基于 Web 的系统,便于你张贴与
Wrox 图书相关的消息和相关技术,与其他读者和技术用户交流心得。该论坛提供了订阅功能,当论坛上有新的消
息时,它可以给你传送感兴趣的论题。
Wrox 作者、编辑和其他业界专家和读者都会到这个论坛上来探讨问题。
http://p2p.wrox.com 上,有许多不同的论坛,它们不仅有助于阅读本书,还有助于开发自己的应用程序。要
加入论坛,可以遵循下面的步骤:
(1) 进入 p2p.wrox.com ,单击 Register 链接。
(2) 阅读使用协议,并单击 Agree 按钮。
(3) 填写加入该论坛所需的信息和自己希望提供的其他信息,单击 Submit 按钮。
(4) 你会收到一封电子邮件,其中的信息描述了如何验证账户,完成加入过程。
加入论坛后,就可以张贴新消息,响应其他用户张贴的消息。可以随时在
Web 上阅读消息。如果要让该网站
给自己发送特定论坛中的消息,可以单击论坛列表中该论坛名旁边的
Subscribe to this Forum 图标。
关于使用
Wrox P2P 的更多信息,可阅读 P2P FAQ ,了解论坛软件的工作情况以及 P2P Wrox 图书的许多常
见问题。要阅读
FAQ ,可以在任意 P2P 页面上单击 FAQ 链接。
源代码
读者在学习本书中的示例时,可以手动输入所有的代码,也可以使用本书附带的源代码文件。本书使用的
不加入 P2P 也可以阅读论坛上的消息,但要张贴自己的消息,就必须加入该论坛。
Visual Studio 2017 高级编程 ( 7 )
VIII
所有源代码都可以从本书合作站点 http://www.wrox.com/ www.tupwk.com.cn/downpage 下载。登录到站点
http://www.wrox.com/ ,使用 Search 工具或使用书名列表就可以找到本书。接着单击本书细目页面上的 Download Code
接,就可以获得所有源代码。另外,也可扫描封底的二维码下载资料。
下载了代码后,只需要用自己喜欢的解压缩软件对它进行解压缩即可。另外,也可以进入
http://www.wrox.
com/dynamic/books/download.aspx
上的 Wrox 代码下载主页,查看本书和其他 Wrox 图书的所有代码。

目 录
第Ⅰ部分 集成开发环境
1 章 快速入门 ···················································· 3
1.1 入门 ································································3
1.1.1 安装 Visual Studio 2017································ 3
1.1.2 运行 Visual Studio 2017································ 7
1.1.3 Visual Studio 真的支持云吗? ····················· 7
1.2 Visual Studio IDE ············································8
1.3
小结 ······························································13
2 Solution Explorer Toolbox
Properties 窗口 ···································· 15
2.1 Solution Explorer 窗口 ··································15
2.1.1 预览文件 ····················································· 18
2.1.2 常见任务 ····················································· 18
2.2 Toolbox
窗口 ·················································26
2.2.1 排列组件 ····················································· 27
2.2.2 添加组件 ····················································· 28
2.3 Properties
窗口 ··············································29
2.4
小结 ······························································33
3 章 选项和定制 ··············································· 35
3.1 Start Page·······················································35
3.2
窗口布局 ·······················································36
3.2.1 查看窗口和工具栏 ····································· 36
3.2.2 停靠 ····························································· 37
3.2.3 保存窗口布局 ············································· 39
3.3
编辑区域 ·······················································40
3.3.1 浏览打开的项 ············································· 41
3.3.2 字体和颜色 ················································· 42
3.3.3 可视化指南 ················································· 42
3.3.4 全屏模式 ····················································· 43
3.3.5 跟踪变化 ····················································· 44
3.4
其他选项 ·······················································44
3.4.1 快捷键 ························································· 44
3.4.2 快速启动 ····················································· 45
3.4.3 项目和解决方案 ········································· 46
3.4.4 Build and Run 界面 ····································· 47
3.4.5 VB 选项 ······················································· 48
3.5
导入和导出设置 ···········································48
3.6
小结 ······························································50
4 Visual Studio 工作区 ·································51
4.1 代码编辑器 ··················································· 51
4.1.1 代码编辑器窗口的布局 ······························ 51
4.1.2 区域 ····························································· 52
4.1.3 大纲 ····························································· 53
4.1.4 代码的格式化 ············································· 53
4.1.5 向前 / 向后浏览 ············································ 54
4.1.6 其他代码编辑器功能 ·································· 54
4.1.7 拆分视图 ····················································· 55
4.1.8 代码窗口的分离 ( 浮动 )······························· 55
4.1.9 复制 Solution Explorer································ 56
4.1.10 创建选项卡组 ··········································· 57
4.1.11 高级功能 ··················································· 58
4.2
代码导航 ······················································· 59
4.2.1 Peek Definition ············································ 59
4.2.2 增强的滚动条 ············································· 60
4.3
命令窗口 ······················································· 63
4.4 Immediate
窗口 ············································· 64
4.5 Class View
工具窗口 ···································· 64
4.6 Error List
窗口 ·············································· 65
4.7 Object Browser
窗口 ····································· 65
4.8
小结 ······························································ 66
5 章 查找和替换以及帮助 ·································67
5.1 Quick Find Quick Replace························ 67
5.1.1 Quick Find ··················································· 67
5.1.2 Quick Replace·············································· 68
5.1.3 查找选项 ····················································· 68
5.1.4 Find and Replace 选项 ································· 69
5.2
文件中查找 / 替换 ·········································· 69
5.2.1 文件中查找 ················································· 69
5.2.2 查找对话框选项 ········································· 70
5.2.3 正则表达式 ················································· 70
5.2.4 结果窗口 ····················································· 72
5.2.5 文件中替换 ················································· 72
5.3
访问帮助 ······················································· 73
5.3.1 浏览和搜索帮助系统 ·································· 73
5.3.2 配置帮助系统 ············································· 74
5.4
小结 ····························································· 74
第Ⅱ部分 入门
6 章 解决方案、项目和项 ·································77
6.1 解决方案的结构 ·········································· 77
6.2
解决方案文件的格式 ··································· 78
6.3
解决方案的属性 ·········································· 79
6.3.1 常规属性 ···················································· 80
6.3.2 配置属性 ···················································· 80
6.4
项目类型 ······················································ 81
6.5
项目文件格式 ·············································· 83
6.6
项目属性 ······················································ 83
6.6.1 Application 选项卡 ····································· 83
6.6.2 Compile 选项卡 ( 仅用于 Visual Basic) ······ 86
6.6.3 Build 选项卡 ( 仅用于 C# F#) ················· 87
6.6.4 Build Events 选项卡 ( 仅用于 C# F#)······ 88
6.6.5 Debug 选项卡 ············································· 88
6.6.6 References 选项卡 ( 仅用于 Visual Basic)··· 89
6.6.7 Resources 选项卡 ······································· 90
6.6.8 Services 选项卡 ·········································· 90
6.6.9 Settings 选项卡 ·········································· 91
6.6.10 Reference Paths 选项卡 ( 仅用于
C# F#)····················································· 91
6.6.11 Signing 选项卡 ········································· 92
6.6.12 My Extensions 选项卡 ( 仅用于
Visual Basic)············································· 92
6.6.13 Security 选项卡 ········································ 93
6.6.14 Publish 选项卡 ········································· 93
6.6.15 Code Analysis 选项卡 ······························ 94
6.7 C/C++ Code Analysis
工具 ··························· 95
6.8 Web
应用程序项目属性 ······························ 96
6.8.1 Web 选项卡 ················································ 96
6.8.2 Package/Publish Web 选项卡 ····················· 96
6.8.3 Package/Publish SQL 选项卡 ····················· 97
6.9 Web Site
项目 ··············································· 97
6.10 NuGet
···················································· 98
6.10.1 NuGet 包管理器 ····································· 98
6.10.2 Package Manager Console······················ 99
6.11
小结 ···························································· 99
7 IntelliSense 和书签 ·································101
7.1 IntelliSense 的解释 ································ 101
7.1.1 通用的 IntelliSense··································· 102
7.1.2 IntelliSense C++ ··································· 103
7.1.3 单词和短语的自动完成 ···························· 103
7.1.4 参数信息 ··················································· 107
7.1.5 快速信息 ··················································· 108
7.2 JavaScript IntelliSense································· 108
7.2.1 JavaScript IntelliSense 上下文 ·················· 108
7.2.2 引用另一个 JavaScript 文件 ····················· 109
7.3 XAML IntelliSense······································ 110
7.4 IntelliSense
选项 ········································· 110
7.4.1 通用选项 ··················································· 110
7.4.2 C# 的特定选项 ··········································· 111
7.5
扩展 IntelliSense ········································· 112
7.5.1 代码片段 ··················································· 112
7.5.2 XML 注释 ················································· 112
7.5.3 添加自己的 IntelliSense···························· 112
7.6
书签和 Bookmarks 窗口 ····························· 113
7.7
小结 ···························································· 114
8 章 代码片段和重构 ·······································115
8.1 代码片段概述 ············································· 115
8.1.1 Toolbox 中存储代码块 ························ 115
8.1.2 代码片段 ··················································· 116
8.1.3 使用 C# 中的代码片段 ······························ 116
8.1.4 VB 中的代码片段 ····································· 117
8.1.5 用代码片段进行封装 ································ 117
8.1.6 Code Snippets Manager ····························· 118
8.1.7 创建代码片段 ··········································· 119
8.1.8 查看已有的代码片段 ································ 119
8.1.9 分布代码段 ··············································· 122
8.2
访问重构支持 ············································· 123
8.3
重构操作 ····················································· 123
8.3.1 Extract Method 重构操作 ·························· 123
8.3.2 Encapsulate Field 重构操作 ······················ 124
8.3.3 Extract Interface 重构操作 ························ 124
8.3.4 Change Signature 重构操作 ······················ 125
8.3.5 Inline Explaining Variables 重构操作 ····· 125
8.3.6 Rename 重构操作 ····································· 126
8.3.7 Simplify Object Initialization 重构操作 ···· 126
8.3.8 Inline Variable Declarations 重构操作 ····· 127
8.3.9 Use‘throw’Expression 重构操作 ··············· 127
8.3.10 Generate Method Stub 重构操作 ············· 128
8.3.11 Remove and Sort Usings 重构操作 ········ 129
8.4
小结 ···························································· 129
9 Server Explorer·······································131
9.1 Servers 连接 ················································ 131
9.1.1 Event Logs 节点 ········································ 132
9.1.2 Message Queues 节点 ································ 133
9.1.3 Performance Counters 节点 ······················· 135
9.1.4 Services 节点 ············································· 137
9.2 Data Connections
节点 ································ 138
9.3 SharePoint Connections 节点 ······················138
9.4
小结 ····························································138
第Ⅲ部分 进阶
10 章 单元测试 ·············································· 141
10.1 第一个测试用例 ·······································141
10.1.1 使用特性标识测试 ······························· 145
10.1.2 其他测试特性 ······································· 145
10.1.3 单元测试和 Code Lens························· 147
10.2
指定判断条件 ···········································148
10.2.1 Assert ··············································· 148
10.2.2 StringAssert ······································ 149
10.2.3 CollectionAssert ······························· 149
10.2.4 ExpectedException 特性 ······················· 149
10.3
初始化和清理 ···········································150
10.3.1 TestInitialize TestCleanup 特性 ········ 151
10.3.2 ClassInitialize ClassCleanup 特性 ···· 151
10.3.3 AssemblyInitialize AssemblyCleanup
特性 ······················································· 151
10.4
测试环境 ···················································151
10.4.1 数据 ······················································· 152
10.4.2 输出测试结果 ······································· 154
10.5 Live Unit Testing ·······································154
10.6
高级单元测试 ···········································155
10.6.1 定制属性 ··············································· 155
10.6.2 测试私有成员 ······································· 156
10.7 IntelliTest···················································157
10.8
小结 ···························································159
11 章 项目模板和项模板 ································ 161
11.1 创建模板 ···················································161
11.1.1 项模板 ··················································· 161
11.1.2 项目模板 ··············································· 164
11.1.3 模板结构 ··············································· 164
11.1.4 模板参数 ··············································· 165
11.1.5 模板位置 ··············································· 166
11.2
扩展模板 ···················································166
11.2.1 模板项目的安装 ··································· 166
11.2.2 IWizard·················································· 166
11.2.3 生成扩展项目模板 ······························· 170
11.3 Starter Kit ··················································171
11.4
联机模板 ···················································171
11.5
小结 ···························································172
12 章 管理源代码 ··········································· 173
12.1 源控制 ·······················································173
12.1.1 选择源控制存储库 ······························· 173
12.1.2 访问源控制 ··········································· 174
12.2
小结 ·························································· 177
第Ⅳ部分 桌面应用程序
13 Windows Form 应用程序 ·······················181
13.1 入门 ·························································· 181
13.2 Windows
窗体 ··········································· 182
13.2.1 Appearance 属性 ······························ 182
13.2.2 Layout 属性 ····································· 183
13.2.3 Window Style 属性 ··························· 183
13.3
窗体设计首选项 ······································· 183
13.4
添加和定位控件 ······································· 184
13.4.1 垂直对齐文本控件 ··························· 185
13.4.2 自动定位多个控件 ··························· 185
13.4.3 控件的 Tab 键顺序和分层 ················ 186
13.4.4 锁定控件设计 ································· 187
13.4.5 设置控件属性 ································· 187
13.4.6 基于服务的组件 ······························ 188
13.4.7 智能标记任务 ································· 188
13.5
容器控件 ··················································· 188
13.5.1 Panel SplitContainer 控件 ·············· 189
13.5.2 FlowLayoutPanel 控件 ······················ 189
13.5.3 TableLayoutPanel 控件 ····················· 190
13.6
停靠和锚定控件 ······································· 190
13.7
小结 ·························································· 191
14 Windows Presentation Foundation
(WPF)····················································193
14.1 WPF 介绍 ················································· 193
14.2
开始使用 WPF·········································· 194
14.2.1 XAML 基础 ···································· 195
14.2.2 WPF 控件 ······································· 196
14.2.3 WPF 布局控件 ································ 197
14.3 WPF
设计器和 XAML 编辑器 ················· 198
14.3.1 使用 XAML 编辑器 ························· 200
14.3.2 使用 WPF 设计器 ···························· 200
14.3.3 Properties 工具窗口 ·························· 202
14.3.4 数据绑定功能 ································· 205
14.4
设置应用程序的样式 ······························· 208
14.5 Windows Forms
的交互操作性 ················· 210
14.5.1 Windows Forms 中驻留 WPF
控件 ··············································· 210
14.5.2 WPF 中驻留 Windows Forms
控件 ··············································· 211
14.6
WPF Visualizer 调试 ···························· 213
14.7
小结 ·························································· 214
15 章 通用 Windows 平台应用程序 ·················215
15.1 Windows 应用程序的定义 ························ 215
15.1.1 呈现内容 ········································· 216
15.1.2 对齐和缩放 ····································· 216
15.1.3 语义式缩放 ····································· 217
15.1.4 磁贴 ··············································· 217
15.1.5 接受云 ············································ 217
15.2
创建 Windows 应用程序 ··························· 217
15.3 Windows
运行库组件 ······························· 222
15.4 .NET Native
编译 ······································ 222
15.5
小结 ··························································· 224
第Ⅴ部分 Web 应用程序
16 ASP.NET Web 窗体 ·······························227
16.1 Web Application 项目和 Web Site 项目 ···· 227
16.2
创建 Web 项目 ·········································· 228
16.2.1 创建 Web Site 项目 ······························· 228
16.2.2 创建 Web Application 项目 ·················· 230
16.3
设计 Web 窗体 ·········································· 233
16.3.1 HTML Designer ···································· 233
16.3.2 定位控件和 HTML 元素 ······················ 234
16.3.3 格式化控件和 HTML 元素 ·················· 235
16.3.4 CSS 工具 ··············································· 237
16.3.5 验证工具 ··············································· 239
16.4 Web
控件 ··················································· 240
16.4.1 导航组件 ··············································· 240
16.4.2 用户身份验证 ······································· 240
16.4.3 数据组件 ··············································· 241
16.5
主页面 ······················································· 243
16.6
富客户端开发 ··········································· 245
16.6.1 JavaScript 开发 ································ 245
16.6.2 使用 ASP.NET AJAX ··························· 246
16.7
小结 ··························································· 248
17 ASP.NET MVC······································249
17.1 Model-View-Controller······························ 249
17.2
开始使用 ASP.NET MVC ························· 250
17.3
选择 Model················································ 252
17.4 Controller
action 方法 ··························· 253
17.5
View 显示 UI········································ 255
17.6
高级 MVC················································· 261
17.6.1 路由 ······················································· 261
17.6.2 action 方法参数 ···································· 264
17.6.3 区域 ······················································· 266
17.6.4 验证 ······················································· 268
17.6.5 部分 View ············································· 269
17.6.6 Dynamic Data 模板 ······························· 270
17.6.7 jQuery ··················································· 272
17.7
小结 ·························································· 273
18 .NET Core·············································275
18.1 .NET Core 的定义 ····································· 275
18.2
使用 ASP.NET Core·································· 276
18.2.1 project.json csproj····························· 277
18.2.2 创建 ASP.NET Core 应用程序 ············· 277
18.3 NuGet
包管理器 ······································· 280
18.4 Bower
包管理器 ······································· 283
18.5
小结 ·························································· 285
19 Node.js 开发 ·········································287
19.1 开始使用 Node.js······································ 287
19.2 Node Package Manager ····························· 291
19.3 Task Runner Explorer ································ 294
19.4
小结 ·························································· 296
20 Python 开发 ··········································297
20.1 Python 入门 ·············································· 297
20.2 Cookiecutter
扩展 ····································· 301
20.3
小结 ·························································· 302
第Ⅵ部分 移动应用程序
21 章 使用 .NET 的移动应用程序 ····················305
21.1 使用 Xamarin············································ 305
21.2
创建 Xamarin Forms 项目 ························ 306
21.3
调试应用程序 ··········································· 308
21.3.1 通用 Windows 平台 ······························ 308
21.3.2 Android ················································· 308
21.3.3 iOS ························································ 316
21.4
小结 ·························································· 318
22 章 使用 JavaScript 的移动应用程序 ···········319
22.1 Apache Cordova 的概念 ···························· 319
22.2
创建 Apache Cordova 项目 ······················· 320
22.2.1 merges 文件夹 ······································ 321
22.2.2 plugins 文件夹 ······································ 321
22.2.3 www 文件夹 ········································· 322
22.2.4 其他文件和文件夹 ······························· 322
22.3
Apache Cordova 中调试 ······················· 325
22.4
小结 ·························································· 327
第Ⅶ部分 云服务
23 Windows Azure·····································331
23.1 Windows Azure 平台 ································· 331
23.1.1 Compute Emulator ······································ 333
23.1.2 角色之间的通信 ········································· 333
23.1.3 应用程序部署 ············································· 335
23.2 SQL Azure·················································337
23.3 Service Fabric············································338
23.4 Azure
移动服务 ········································339
23.5 Azure
虚拟机 ············································340
23.5.1 连接性 ························································· 340
23.5.2 端点 ····························································· 340
23.5.3 虚拟网络 ····················································· 340
23.6
小结 ···························································341
24 章 同步服务 ·············································· 343
24.1 偶尔连接的应用程序 ································343
24.2 Server Direct··············································344
24.3
同步服务入门 ···········································346
24.4 N
层上的同步服务 ····································349
24.5
小结 ···························································350
25 SharePoint··········································· 351
25.1 SharePoint 执行模型 ·································351
25.1.1 场解决方案 ················································· 351
25.1.2 沙箱解决方案 ············································· 352
25.1.3 应用程序模型 ············································· 352
25.2
准备开发环境 ···········································352
25.3
创建 SharePoint 项目 ································354
25.4
运行应用程序 ···········································359
25.5
小结 ···························································361
第Ⅷ部分 数据
26 章 可视化数据库工具 ································ 365
26.1 Visual Studio 2017 中的数据库窗口 ·········365
26.1.1 Server Explorer 窗口 ··································· 365
26.1.2 Data Sources 窗口 ······································· 368
26.1.3 SQL Server Object Explorer ······················· 369
26.2
编辑数据 ···················································369
26.3 Redgate
数据工具 ·····································370
26.3.1 ReadyRoll Core··········································· 370
26.3.2 SQL Prompt Core········································ 373
26.3.3 SQL Search·················································· 374
26.4
小结 ···························································375
27 ADO.NET Entity Framework ················ 377
27.1 什么是 Entity Framework··························377
27.2
入门 ···························································378
27.3
创建实体模型 ···········································378
27.3.1 实体数据模型向导 ····································· 378
27.3.2 Entity Framework 设计器 ·························· 381
27.3.3 创建 / 修改实体 ············································ 384
27.3.4 创建 / 修改实体关联 ···································· 386
27.3.5 实体继承 ····················································· 387
27.3.6 验证实体模型 ············································· 387
27.3.7 根据数据库的修改来更新实体模型 ········ 387
27.4
查询实体模型 ··········································· 387
27.4.1 LINQ to Entities 概述 ································· 388
27.4.2 获得对象上下文 ········································· 388
27.4.3 CRUD 操作 ················································· 388
27.4.4 导航实体关联 ············································· 391
27.5
高级功能 ··················································· 392
27.5.1 从实体模型更新数据库 ···························· 392
27.5.2 给实体添加业务逻辑 ································· 393
27.5.3 POCO ·························································· 393
27.5.4 Entity Framework Core······························· 393
27.6
小结 ·························································· 393
28 章 数据仓库和数据湖 ·································395
28.1 Apache Hadoop 的概念 ····························· 395
28.1.1 Hadoop 分布式文件系统 ··························· 395
28.1.2 MapReduce·················································· 396
28.1.3 其他组件 ····················································· 396
28.1.4 HDInsight···················································· 396
28.1.5 Azure 数据湖 ·············································· 396
28.2 Visual Studio
的数据湖工具 ····················· 397
28.2.1 创建 Hive 应用程序 ··································· 398
28.2.2 创建 Pig 应用程序 ····································· 400
28.3
小结 ·························································· 403
29 章 数据科学和分析 ····································· 405
29.1 R 的概念 ····················································405
29.2 R Tools For Visual Studio ···························405
29.2.1 调试 R 脚本 ················································· 407
29.2.2 工作区 ·························································· 409
29.2.3 绘图窗口 ······················································ 410
29.3
小结 ···························································411
第Ⅸ部分 调试
30 章 使用调试窗口 ········································ 415
30.1 代码窗口 ····················································415
30.1.1 断点 ······························································ 415
30.1.2 数据提示 ······················································ 415
30.2 Breakpoints
窗口 ········································416
30.3 Output
窗口 ················································416
30.4 Immediate
窗口 ··········································417
30.5 Watch 窗口 ················································ 418
30.5.1 QuickWatch 窗口 ········································· 418
30.5.2 Watch 1-4 窗口 ············································· 419
30.5.3 Autos 窗口和 Locals 窗口 ·························· 419
30.6
代码执行窗口 ··········································· 419
30.6.1 Call Stack 窗口 ············································· 419
30.6.2 Threads 窗口 ················································ 420
30.6.3 Modules 窗口 ··············································· 420
30.6.4 Processes 窗口 ·············································· 420
30.7 Memory
窗口 ············································ 421
30.7.1 Memory 1-4 窗口 ········································· 421
30.7.2 Disassembly 窗口 ········································ 421
30.7.3 Registers 窗口 ·············································· 422
30.8
并行调试窗口 ··········································· 422
30.8.1 Parallel Stacks 窗口 ······································ 423
30.8.2 Parallel Tasks 窗口 ······································· 424
30.9 Exceptions
窗口 ········································ 425
30.10
小结 ························································· 426
31 章 断点调试 ···············································427
31.1 断点 ··························································· 427
31.1.1 设置断点 ······················································ 427
31.1.2 添加中断条件 ·············································· 428
31.1.3 断点操作 ······················································ 430
31.2
跟踪点 ······················································· 431
31.3
执行控制 ··················································· 432
31.3.1 单步执行代码 ·············································· 432
31.3.2 Run to Cursor 功能 ······································ 433
31.3.3 移动执行点 ·················································· 434
31.4 Edit and Continue
功能 ······························ 434
31.4.1 原始编辑 ······················································ 434
31.4.2 停止应用修改 ·············································· 434
31.5
小结 ··························································· 434
第Ⅹ部分 构建和部署
32 章 升级到 Visual Studio 2017 ····················437
32.1 从最近的 Visual Studio 版本升级 ············ 437
32.2
升级到 .NET Framework 4.6.2··················· 439
32.3
小结 ··························································· 440
33 章 定制构建 ···············································441
33.1 通用构建选项 ··········································· 441
33.2
手动配置依赖关系 ··································· 443
33.3 Visual Basic
编译页面 ······························· 444
33.3.1 高级编译器设置 ·········································· 444
33.3.2 构建事件 ······················································ 445
33.4 C#
构建页面 ···············································446
33.5 MSBuild·····················································448
33.5.1 Visual Studio 使用 MSBuild 的方式 ·········· 448
33.5.2 MSBuild 模式 ·············································· 450
33.5.3 通过 MSBuild 任务设置程序集的
版本
··························································· 451
33.6
小结 ···························································452
34 章 模糊处理、应用程序监控和管理 ············ 453
34.1 IL 反编译器 ···············································453
34.2
反编译器 ····················································454
34.3
模糊处理代码 ············································455
34.3.1 Dotfuscator ··················································· 455
34.3.2 模糊处理特性 ·············································· 459
34.3.3 警告 ······························································ 460
34.4
应用程序监控和管理 ································462
34.4.1 防篡改功能 ·················································· 462
34.4.2 应用程序检测和分析功能 ························· 463
34.5
小结 ···························································464
35 章 打包和部署 ············································ 465
35.1 Windows Installer XML 工具集 ·················465
35.1.1 构建安装程序 ·············································· 466
35.1.2 使用 Heat 创建片段 ···································· 468
35.1.3 服务安装程序 ·············································· 470
35.2 ClickOnce
技术 ··········································470
35.2.1 部署 ······························································ 471
35.2.2 升级 ······························································ 473
35.3
小结 ···························································474
36 Web 应用程序的部署 ···························· 475
36.1 Web 部署 ···················································475
36.1.1 发布 Web 应用程序 ···································· 475
36.1.2 发布到 Azure··············································· 477
36.2 Web
项目安装程序 ····································479
36.3 Web Platform Installer ································480
36.4
小结 ···························································483
37 章 持续交付 ··············································· 485
37.1 定义术语 ····················································485
37.1.1 持续交付 ······················································ 485
37.1.2 持续集成 ······················································ 486
37.1.3 DevOps························································· 486
37.2
持续交付工具 ············································486
37.2.1 设置持续交付 ·············································· 487
37.2.2 Heads Up Code Analysis······························ 488
37.2.3 自动构建通知 ·············································· 489
37.3
小结 ···························································491
目 录
XV
第Ⅺ部分 Visual Studio 版本
38 Visual Studio Enterprise :代码质量 ······495
38.1 依赖验证 ··················································· 495
38.2
使用 Code Map 研究代码 ························· 499
38.3
代码克隆 ··················································· 500
38.4
小结 ··························································· 500
39 Visual Studio Enterprise :测试和
调试
·······················································501
39.1 自动测试 ··················································· 501
39.1.1 Web 性能测试 ·············································· 501
39.1.2 负载测试 ······················································ 503
39.1.3 编码 UI 测试 ················································ 505
39.1.4 一般测试 ······················································ 506
39.1.5 有序测试 ······················································ 506
39.2 IntelliTrace ················································ 506
39.3 IntelliTest ···················································509
39.4
小结 ···························································510
40 Visual Studio Team Service ·················· 511
40.1 Git 入门 ·····················································511
40.2
版本控制 ····················································513
40.2.1 提交 ······························································ 514
40.2.2 分支 ······························································ 514
40.2.3 同步 ······························································ 515
40.3
工作项跟踪 ················································515
40.3.1 工作项查询 ·················································· 516
40.3.2 工作项类型 ·················································· 517
40.3.3 添加工作项 ·················································· 517
40.3.4 工作项状态 ·················································· 518
40.4 Build ··························································518
40.5
门户网站 ····················································519
40.6
小结 ···························································519

第Ⅰ 部分
集成开发环境
¾ 1 章 快速入门
¾ 2 Solution Explorer Toolbox Properties 窗口
¾ 3 章 选项和定制
¾ 4 Visual Studio 工作区
¾ 5 章 查找和替换以及帮助

第一章

快速入门

本章内容
安装并开始使用 Visual Studio 2017
创建并运行你的第一个应用程序
调试并部署应用程序
自从开始开发软件以来,就需要使用工具来帮助我们编写、编译、调试和部署应用程序。
Visual Studio 2017
最佳组合的集成开发环境
(Integrated Development Environment IDE) 继续演化的下一个版本。
本章介绍
Visual Studio 2017 的用户体验,并学习使用各种菜单、工具栏和窗口。作为 IDE 的快速入门,本章
不会详细列举每一个可以更改的设置,也不会介绍如何自定义
IDE 的布局,因为这些主题会在后续章节中讨论。
1.1 入门
Visual Studio 近来的一些版本在安装体验上已逐渐改进,不过 Visual Studio 2017 已经完全更新了安装选项和工
作流。这样设计不仅旨在快速进入
Visual Studio 并运行,而且可以让你轻松选择安装自己需要的选项。本节介绍安
装过程,并开始使用
IDE
1.1.1 安装 Visual Studio 2017
Microsoft Visual Studio 2017 的安装程序称为“低影响的安装程序 (low-impact installer) ”。在比较了 Visual
Studio 2015
占用的空间与用户请求的体验和正在使用的体验之后, Microsoft 团队产生了创建一个“低影响的安装
程序”的想法。可能令人惊讶的是,并不是每个开发人员都需要
Visual Studio Windows Forms ASP.NET WPF
Universal Apps 以及 C++ 的支持。
Microsoft Visual Studio 2015 及其早期的版本都进行了优化,按 F5 键就可以立即运行程序。要运行大多数 .NET
应用程序并不需要安装其他任何组件。虽然这只是有关易用性的一次显著增强,但确实是 Visual Studio 的一次具有
纪念意义的重大转变
( 有些人可能会说这是在鼓吹 )
Visual Studio 2017 的安装过程具有一些不同的方面。将自动安装“所有一切”改为可以根据安装的需要选取不
同的组件。确实,这一过程相对于过去有所不同,但现在可以选择安装的组件选项增加了很多。不过,更多的选项
并不意味着能得到更好的安装体验。实际上,当你试图从一百个不同的选项中挑选出项目所需的选项时,体验可能
会很糟糕。为了解决这个问题,
Visual Studio 2017 安装程序使用了工作负载 (workload) 的概念。
当启动
Visual Studio 2017 安装程序 ( 该程序仅有 2MB 大小 ) 时,会快速显示如图 1-1 所示的对话框。自然,该对
话框的出现是在阅读
( 当然要详细阅读 ) 并接受许可信息和隐私声明之后。
1

该对话框是安装程序的主要界面,可以在其中指定所期望组件的安装位置。组件的指定存在两种模式。图 1-1
中的工作负载被分成 5 个不同的类别。为在安装过程中包含工作负载,只需要单击该对话框,就会在右上角显示一
个蓝色的复选框。可以在安装过程中添加任意数量的工作负载。其中常用的工作负载如下。
Universal Windows Platform development : 如果要为 Universal Windows Platform 创建应用程序,而不考
虑语言的选择,就可以使用该工作负载。
.NET desktop development : 允许使用 WPF Windows Forms 创建应用程序。 Console 应用程序模板也
包含在该工作负载中。
Desktop development with C++ : 用于构建经典的基于 Windows 的应用程序。如果期望使用 Visual C++
Active Template Library(ATL) Microsoft Foundation Classes(MFC) ,该选项就非常合适。
ASP.NET and web development : 添加用于构建 Web 应用程序的组件,包括 ASP.NET ASP.NET Core
和简单的旧式 HTML/JavaScript/CSS
Azure development : 包含 Azure SDK 、一些工具和项目模板,允许创建基于 Azure 的云应用程序。
Python development : 包含对 cookiecutter Python 3 ,以及用于与 Azure 交互的工具的支持。另外,也可
以可选地包含
Python 的其他发布版本,如 Anaconda
Node.js development Visual Studio 2017 支持的新工具之一,其中包含的组件允许使用 Node.js 平台创建
网络应用程序。
Data storage and processing Azure 平台近来一些新增的组件,包括 Azure Data Lake Hadoop Azure
ML(Machine Learning
,机器学习 ) 。该工作负载包括一些用于为 Azure 平台和 Azure SQL Server 数据库开
发应用程序的模板和工具。
Data science and analytical applications : 可以将 R Python F# 这三种语言一起带入其他工作负载。可
以使用这些工具构建各种基于分析的应用程序。
Office/SharePoint development : 用于构建各种 Office SharePoint 应用程序,包括 Office 加载项、
SharePoint 解决方案和 Visual Studio Tools for Office(VSTO) 加载项。
Mobile development with .NET Visual Studio 2017 所支持的三种移动开发技术之一,允许使用 Xamarin
创建 iOS Android Windows 应用程序。
Mobile development with JavaScript : 与 Mobile development with .NET 类似,但该工作负载不使用
Xamarin ,而是使用 Tools for Apache Cordova JavaScript 来开发应用程序。
Mobile development with C++ : 三种移动开发环境之一,允许使用 C++ 创建 iOS Android Windows
应用程序。
Game development with Unity Unity 是一个使用广泛且具有极灵活跨平台功能的游戏开发环境。该工作
负载允许使用
Unity 框架创建 2D 3D 游戏。
Game development with C++ : 支持使用 C++ DirectX Unreal Cocos2d 等库创建游戏。
Visual Studio extension development : 允许创建可在 Visual Studio 中使用的增件和扩展。其中包括代码分
析器和工具窗口,它们利用了
Roslyn 编译器功能。
Linux development with C++ Windows 10 包含了一个安装基于 Ubuntu Linux Bash shell 的选项。该工
作负载包含的一组工具和库用于创建在
Linux 中使用 Visual Studio 运行的应用程序。
.NET Core cross-platform development .NET Core 是进行跨平台开发的一种流行方法。该工作负载允许
创建
.NET Core 应用程序,包括 Web 应用程序。
本书中使用的工作负载
要运行本书中的示例,需要安装一些工作负载。特别是:
● Universal Windows Platform
● .NET desktop development
● ASP.NET and web development
● Azure development
● Node.js development
● Data storage and processing
● Data science and analytical applications
● Mobile development with .NET
● Mobile development with JavaScript
● .NET Core cross-platform development
用于选择组件的第二种模式则是更细粒度的。如果在安装屏幕的顶部选择了 Individual components 链接,就会
出现图
1-2 所示的组件列表。可以从该列表中选择希望安装在机器上的任意组件。


Visual Studio 的第三个安装选项包含一个或多个所支持的语言包。单击 Language packs 链接会显示可用的语言
包列表,如图
1-3 所示。

一旦选择了组件 ( 单个组件或工作负载中的组件 ) ,就可以选择安装位置并单击 Install 按钮。之后将进入长时间
的安装过程。所出现的安装进度对话框如图
1-4 所示。根据已安装到计算机上的组件,在安装过程中或结束时可能
会提示用户重启计算机。成功安装好所有组件后,原来的对话框会有少许变化,如图
1-5 所示。若将来要为 Visual
Studio
添加新功能,则可以通过这个对话框逐渐添加。

要弄清楚工作负载和所包含的更细粒度组件之间的关系,只需要选择一个工作负载即可。包含在其
中的组件列表出现在图
1-2 右侧的窗格中。

1-5
1.1.2 运行 Visual Studio 2017
第一次运行 Visual Studio 2017 时,就有机会登录,如图 1-6 所示。如果已经在 Visual Studio 2017 中登录,系统
则不会提示你登录,因为版本之间会记住登录凭据。但如果你之前没有登录过
Visual Studio ,则会被要求提供
Microsoft Live 账户。
这种行为是
Visual Studio 支持云的努力的一部分——把 Visual Studio 设置和功能连接到互联网上可用的资产
上。这不需要登录。登录页面中包含了
Not Now, Maybe Later 链接。
单击该链接,跳过一些步骤,可很快进入
Visual Studio 。但登录也有一些优点。
1.1.3 Visual Studio 真的支持云吗?
简洁的回答是“支持”。更准确的回答是“支持,如果需要的话”。在创建这个功能时, Microsoft 研究工作的一
部分涉及理解开发人员如何识别各种在线功能。一般来说,大多数开发人员都有两个或多个在开发时使用的
Microsoft 账户。他们有一个主要的身份,一般映射到工作时使用的凭据。他们还有其他身份,用于访问外部功能,
比如
Team Foundation Server ,或者把应用程序发布到不同的 Microsoft stores
为了模仿开发人员如何使用多个在线身份,
Microsoft Visual Studio 中给这些身份之间引入了一个层次关系。
登录时,指定的账户是用于
Visual Studio IDE 的主要身份。从理论上来说,它应该代表开发人员。用同一个凭据登
录到
Visual Studio 的任何地方,首选设置都不变,包括主题和键盘绑定等自定义设置。对一个设备的改变会自动反
映到已登录的其他设备。
为处理二级凭据,
Visual Studio 2017 包含了一个安全凭据库。这允许记录并使用到外部服务的连接,而不必每
次都提供身份验证。当然,可以从特定的连接中手动注销,并删除凭据。
作为云支持的一部分,用户名会显示在
IDE 的右上角 ( 假设已登录 ) 。如果单击下拉箭头 ( 如图 1-6 所示 ) ,就会
看到
Account settings 链接。单击该链接,会打开一个对话框 ( 如图 1-7 所示 ) ,在这里可以管理账户的细节,包括将
Visual Studio 与不同的账户关联起来。

1-6

1-7
除提供一种机制来编辑配置文件的基本联系信息外,该对话框还包含一个已被当前机器“记住”的 Microsoft Live
账户列表。
1.2 Visual Studio IDE
第一次启动 Visual Studio 2017 时, 会显示一个对话框, 指示 Visual Studio 正在配置开发环境。 当该过程完成时,
将打开
Visual Studio 2017 ,此时就可以开始工作了,如图 1-8 所示。

1-8
在屏幕的中心会显示 Start 页面。该页面包含的链接可执行大多数常见的功能。例如,其中包含一个 Recent
目列表以及一些允许打开现有项目或创建新项目的链接。这些链接显示了一些最常用的模板。之前版本的
Start
面包括了开发人员感兴趣的新闻反馈
(news feed) ,新版的 Visual Studio 2017 仍然保留了这一部分。在该页面左上角
Get Started 部分,其中包含的链接则提供了一些有益于 Visual Studio 新用户的信息。
在开始生成你的第一个应用程序之前,应先回过头来看看组成
Visual Studio 2017 IDE 的组件。菜单和工具栏位
IDE 的顶部,一系列子窗口或窗格显示在主窗口区域的左侧、右侧和底部。在其中心是主编辑区域。只要打开代
码文件、
XML 文档、窗体或其他文件,它们都会显示在这个区域中以供编辑。每打开一个文件都会创建一个新的
选项卡,以便在这些打开的文件之间进行切换。
在编辑区域的两侧是一组工具窗口:这些区域提供了额外的上下文信息和功能。对于一般的开发人员设置,默
认的布局包括:右侧有
Solution Explorer Properties ,左侧有 Server Explorer Toolbox 。左侧的工具窗口处于折
( 或取消固定 ) 状态。如果单击某个工具窗口的标题,该窗口就会展开,当它不再是焦点或把光标移到屏幕的另一
个区域时,该窗口会再次折叠起来。工具窗口展开时,在其右上角会显示
3 个图标,如图 1-9 的右上角所示。

如果希望工具窗口保持展开 ( 或固定 ) 状态,可以单击中间的图标,它看起来像一个图钉。当这个图钉旋转 90 °
时,表示该窗口现在被固定了。单击第
3 个图标“×”,就会关闭窗口。如果以后想要再次打开这个窗口或另一个
工具窗口,可从
View 菜单中选择。
单击第一个图标
( 向下箭头 ) 时,会显示一个上下文菜单。这个列表中的每一项都表示工具窗口的一种不同的排列方
式。如你所想,
Float 选项可以把工具窗口放在屏幕的任意位置,独立于主 IDE 窗口。如果有多个屏幕, Float 选项就比
较有效,因为可以把各个工具窗口移到其他屏幕上,让编辑区域使用最大的屏幕空间。选择
Dock as Tabbed Document
项会把工具窗口变成编辑区域的一个附加选项卡。第
4 章将介绍如何通过停靠工具窗口来高效地管理工作区。
开发、生成、调试和部署第一个应用程序
概览了 Visual Studio 2017 IDE 之后,本节介绍如何逐步创建一个简单的应用程序来演示如何使用其中的一些组件。
当然,这是每个开发人员都必须掌握的
Hello World 示例,根据用户的习惯,可以用 Visual Basic .NET C# 来完成。
(1) 首先选择 File | New | Project 命令,打开 New Project 对话框,如图 1-10 所示。对话框的左侧有一个树状结
构,用于根据语言和技术分组模板。右上角还有一个搜索框。这个对话框的右窗格显示了所选项目模板的其他信息。
最后,通过对话框顶部的下拉列表,可以选择应用程序所面向的
.NET Framework 版本。
一些工具窗口不能通过 View 菜单来访问,例如与调试相关的窗口,如线程和观察窗口。在大多数
情况下,这些窗口可以通过另一个菜单项来访问。对于调试窗口而言,就是
Debug 菜单。

1-10
Templates 区域选择 WPF Application( 这一项在根节点 Visual Basic Visual C# 下,或在子节点 Windows
) ,将 Name 设置为 GettingStarted ,之后单击 OK 按钮。这将创建一个新的 WPF 应用程序项目,它包括一个开
始窗口并包含在解决方案
Chapter 1 中,如图 1-11 Solution Explorer 窗口中所示。这个开始窗口自动在可视化
设计器中打开,给出了运行应用程序时窗口大致的图形化外观。
Properties 工具窗口会折叠,并位于工具窗口的
右侧。

1-11
(2) 单击折叠的 Toolbox 窗口,其显示在屏幕的左侧。这会展开 Toolbox 窗口。然后单击图钉图标,固定该工
具窗口。要在
GettingStarted 项目的窗口中添加控件,可以从 Toolbox 中选择相应的项并拖放到窗体上。还可以双击
该项,
Visual Studio 会自动把它们添加到窗体上。
(3) 在窗体上添加一个按钮和一个文本框,布局应如图 1-12 所示。选择文本框,再选择 Properties 工具窗口 (
F4 键会自动打开 Properties 工具窗口 ) 。把该控件的名称设置为 txtSayHello( 显示在 Properties 工具窗口的顶部 )
Button 控件重复这个操作,把它命名为 btnSayHello ,将其 Content 属性设置为“ Say Hello! ”。

Name 字段下面的搜索字段中输入一个属性名,就可以快速定位该属性。在图 1-12 中输入 Conten ,以缩短
Properties 列表,更容易找到 Content 属性。
在窗口上添加控件后,选项卡的文本后面就会加上星号
(*) ,表示这个选项卡有未保存的修改。如果试图在修改
内容处于挂起状态时关闭这个选项卡,
Visual Studio 会询问是否要保存这些修改。生成应用程序时,任何未保存的
文件都会自动保存为生成过程的一部分。
(4) 取消对所有控件的选择 ( 单击屏幕上的空白区域即可 ) ,再双击按钮。这不仅会在代码编辑器中打开这个窗
体的代码隐藏文件,还会给按钮创建
Click 事件的处理程序。添加一行代码,给用户回应一条消息后,代码窗口如
1-13 所示。

需要注意的是,在 Visual Studio 2017 中进行修改时,一些文件也会改变,如解决方案文件,但不显

示任何已改变的指示。如果试图退出应用程序或关闭解决方案, Visual Studio 仍会提示保存这些修改。
(5) 在生成并执行应用程序之前,把光标放在包含 MessageBox.Show 的代码行上,按下 F9 键。这将设置一个
断点——按下
F5 键运行应用程序,然后单击“ Say Hello !”按钮后,会在这一行上暂停应用程序的执行。图 1-14
显示程序的执行正到达这个断点。把鼠标指针悬停在这一断点行上,就会出现一个数据提示,显示 txtSayHello.Text
属性的内容。

在图 1-14 中, Visual Studio 的布局与前面的屏幕截图完全不同, 因为这个屏幕的下半部分显示了许多工具窗口,
顶部显示了一些命令栏。另外,
IDE 底部的状态栏是橙色的,而当处于设计模式时,显示为蓝色。当停止运行或调
试应用程序时,
Visual Studio 会返回到以前的布局。 Visual Studio 2017 维护着两个分开的布局:设计时布局和运行
时布局。当编辑项目时,菜单、工具栏和各个窗口使用默认布局;而执行和调试项目时,它们都定义了不同的设置。
可以修改这些布局,以适应自己的风格,并且
Visual Studio 2017 会记住这些修改。
(6) 需要部署你的应用程序。无论是使用 Windows Forms WPF 生成富客户端应用程序,还是使用 IIS(Internet
Information Services)
Azure Node.js 或任何其他的技术生成 Web 应用程序, Visual Studio 2017 都可以发布该应用程
序。在
Solution Explorer 中双击 Properties 节点,选择 Publish 节点,就会显示发布应用程序的选项,如图 1-15 所示。

在图 1-15 中,发布文件夹被设置为本地路径 ( 默认情况下,该路径相对于项目所在的目录 ) ,但可以指定网络文
件夹、
IIS 文件夹或 FTP 站点。一旦指定了要发布的位置,单击 Publish Now 按钮就会把应用程序发布到该位置。
1.3 小结
本章介绍了 Visual Studio 2017 的各个组件如何协调工作以生成应用程序。下面列出创建解决方案的一般
过程:
(1) File 菜单创建解决方案。
(2) Solution Explorer 定位需要编辑的窗口,双击该项,在主工作区显示它。
(3) 把需要的组件从 Toolbox 拖放到窗口上。
(4) 依次选择窗口和各个组件,在 Properties 窗口中编辑属性。
(5) 双击窗口或控件,访问组件的图形化界面背后的代码。
(6) 用主工作区编写代码,并设计图形化界面,在该区域的顶部通过选项卡切换它们。
(7) 用工具栏启动程序。
(8) 如果出错,就在 Error List Output 窗口中复查。
(9) 用工具栏或菜单命令保存项目,并退出 Visual Studio 2017
后续章节将介绍如何定制
IDE ,使其更符合自己的工作风格,还将说明 Visual Studio 2017 如何完成应用程序开
发过程的大量工作。本书还会介绍作为开发人员使用
Visual Studio 2017 时可重用的许多最佳实践。
第Ⅲ部分
进 阶
¾ 10 章 单元测试
¾ 11 章 项目模板和项模板
¾ 12 章 管理源代码

单 元 测 试
本章内容
从已有代码中生成测试工具
判断代码的行为
在测试生命周期事件中执行定制代码
创建数据驱动的测试
测试私有成员
利用 Live Unit Testing
本章源代码下载
通过在 www.wrox.com 网站上搜索本书的 EISBN (978-1-119-40458-3) ,可以下载本章的源代码。相关源代码
和支持文件都在本章对应的文件夹中。
在软件开发过程中,应用程序的测试是最重要的部分之一。对软件维护费用的调查数据显示,在生产阶段进行测
试所需的软件检测费用至多可以达到在开发阶段进行测试的
100 ( 该数据来源于 IBM 公司 System Sciences Institute
提供的报表 ) 。同时,许多测试涉及每次修改基本代码都必须进行的重复、枯燥、易出错的工作,避免这种情况最
简单的对策是生成可重复的自动化测试,由计算机根据需要执行。本章将讨论一种特殊类型的自动测试技术,它主
要用于测试系统中独立的组件或单元。如果有一套自动化单元测试,那么可在对各个组件进行大幅修改后,验证它
们是否像预期的那样工作。
Visual Studio 2017 有一个内置框架,可以编写、执行和汇报测试用例。本章主要介绍单元测试的创建、配置、
运行和管理,并说明如何通过测试数据集进行测试。
10.1 第一个测试用例
测试用例的编写很难实现自动化,这是因为测试用例必须对应于所开发软件的功能。事实上,人们经常争论是
否自动执行除了最简单的单元测试之外的其他测试用例。但是,在测试过程的某些阶段中,可以通过工具生成一些
代码存根。为了说明这一点,先来看一段相对简单的代码片段,学习如何编写测试用例代码。假定
Subscription
有一个
CurrentStatus 公有属性,该属性把当前的订阅状态返回为一个枚举值。
VB
Public Class Subscription
Public Enum Status
Temporary
Financial



10
第Ⅲ部分 进 阶
142
Unfinancial
Suspended
End Enum
Public Property PaidUpTo As Nullable(Of Date)
Public ReadOnly Property CurrentStatus As Status
Get
If Not Me.PaidUpTo.HasValue Then Return Status.Temporary
If Me.PaidUpTo > Now Then
Return Status.Financial
Else
If Me.PaidUpTo >= Now.AddMonths(-3) Then
Return Status.Unfinancial
Else
Return Status.Suspended
End If
End If
End Get
End Property
End Class
C#
{
public enum Status
{
Temporary,
Financial,
Unfinancial,
Suspended
}
public DateTime? PaidUpTo { get; set; }
public Status CurrentStatus
{
get
{
if (this.PaidUpTo.HasValue == false)
return Status.Temporary;
if (this.PaidUpTo > DateTime.Today)
return Status.Financial;
else
{
if (this.PaidUpTo >= DateTime.Today.AddMonths(-3))
return Status.Unfinancial;
else
return Status.Suspended;
}
}
}
}
从上面的代码片段可以看出,需要从 4 个代码路径对 CurrentStatus 属性进行测试。为此,必须在一个新的测试
项目中创建另一个
SubscriptionTest 测试类,在该类中添加一个测试方法,该方法包含的代码用于实例化一个
Subscription 对象,设置 PaidUpTo 属性,检查 CurrentStatus 属性是否包含正确的结果。接着,继续添加测试方法,
直到执行并测试了涉及该属性的每一个代码路径。
Visual Studio 2017 包含一个可帮助创建单元测试的工具,用于测试现有的类。该工具可以创建一个测试项目和许
多方法,这些方法很容易通过一些基本步骤来运行类。相关的详细内容请参见
10.7 节。然而,即使有一个工具可以
帮助生成单元测试,也仍需要知道是什么使某个方法变成单元测试。
Visual Studio 提供了一个运行时引擎,该引擎可
用于运行测试用例,监控其工作进度,报告测试结果。因此,开发人员只需要编写代码来测试存在疑问的属性即可。

要查看测试类的基本模板,需要确保在 Solution Explorer 中选择测试项目,然后选择 Project | Add Unit Test 。这
会创建一个测试类和单个测试方法。
Unit Test 模板仅包括一个基本的单元测试类,该类仅包含单个方法,如下面的
代码示例所示。对于该示例,已经将测试类命名为
SubscriptionTest( 而非默认的 UnitTest1) ,以表明这是一个测试类:
VB
Imports Microsoft.VisualStudio.TestTools.UnitTesting
<TestClass()>
Public Class SubscriptionTest
<TestMethod()>
Public Sub TestMethod1()
End Sub
End Class
C#
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
[TestClass]
public class SubscriptionTest
{
[TestMethod]
public void TestMethod1()
{
}
}
虽然有很多技术可用来编写自己的单元测试,但是应该注意两个主要的理念。第一个理念是,如果项目中有大
量的单元测试,那么很快就会变得难以管理。为解决该问题,建议使用命名约定。如你所料,可使用许多不同的命
名约定,但一种流行的约定是
MethodName_ StateUnderTest_ExpectedBehavior 。这种简单的命名约定确保可以轻松
地查找和标识测试用例。
第二个理念是使用
Arrange/Act/Assert 范例处理每个测试。首先设置并初始化用于测试中的值 (Arrange 部分 )
然后执行测试的方法
(Act 部分 ) ,最后确定测试的结果 (Assert 部分 ) 。如果遵循该方法,最终会得到如下的单元测试:
VB
<TestMethod()>
Public Sub CurrentStatus_NothingPaidUpToDate_TemporaryStatus()
' Arrange
Dim s as New Subscription()
s.PaidUpTo = Nothing
' Act
Dim actual as Subscription.Status = s.CurrentStatus
' Assert
Assert.Inconclusive()
End Sub
C#
[TestMethod]
public void CurrentStatus_NullPaidUpToDate_TemporaryStatus()
{
// Arrange
Subscription s = new Subscription();
s.PaidUpTo = null;
// Act
Subscription.Status actual = s.CurrentStatus;
//Assert
Assert.Inconclusive();
}

在进一步学习之前,运行此测试用例以查看发生的情况,方法是在代码窗口右击该用例并选择 Run Tests 。此时
会打开
Test Explorer 窗口,如图 10-1 所示。

从图 10-1 中可以看到, 测试用例返回了一个不确定的结果。警告图标 ( 包含感叹号的三角形 ) 表示该测试被跳过。
10-1 右侧的有关测试结果的详细描述中,有一条消息表明 Assert.Inconclusive 失败。从本质上讲,这表明该测试
是不完整的或者其结果不可信赖,因为某些修改会使该测试无效。结果显示了测试的基本信息、结果和其他有用的
环境信息,如计算机名和测试的执行持续时间。
在创建此单元测试时, 手动插入
Assert.Inconclusive 语句。 要完成此单元测试, 必须实际地执行适当的结果分析,
以确保顺利通过测试。具体实现方式是用
Assert.AreEqual 替换 Assert.Inconclusive 语句,如下面的代码所示:
VB
<TestMethod()>
Public Sub CurrentStatus_NothingPaidUpToDate_TemporaryStatus ()
Dim target As Subscription = New Subscription
Dim actual As Subscription.Status
actual = target.CurrentStatus
Assert.AreEqual(Subscription.Status.Temporary, actual, _
"Subscription.CurrentStatus was not set correctly.")
End Sub
C#
[TestMethod()]
public void CurrentStatus_NullPaidUpToDate_TemporaryStatus ()
{
Subscription target = new Subscription();
Subscription.Status actual;
actual = target.CurrentStatus;
Assert.AreEqual(Subscription.Status.Temporary, actual,
"Subscription.CurrentStatus was not set correctly.");
}
尽管从到目前为止所完成的工作中还不能明显看出来,但需要知道完整的测试可划分为 3 个类别之一: Failed
Tests
Passed Tests Not Run Tests 。可以运行所有的测试、只运行特定类别中的测试、重复运行最后一个测试,或
者仅运行所选择的测试。
Test Explorer 顶部的 Run 链接包含一个下拉列表,从中可以选择要运行的测试类别。要选
择运行个别测试, 可单击所需的测试
( 使用标准的 Ctrl+ 单击或 Shift+Ctrl+ 单击操作, 在第一个测试后添加其他测试 )
然后右击并选择
Run Selected Tests 。修正造成测试失败的代码之后,单击 Run All 按钮,以重新运行这些测试用例,
并产生成功的结果,如图
10-2 所示。
上下文菜单仅是选择并运行测试用例的一种方式。还有一个 Test 菜单,其中包含 Run 子菜单,可
用于执行所有或选择的测试。或者,可直接打开
Test Explorer 窗口,并使用链接运行所有或选择的测
( 参见图 11-1) 。除了这些方法之外,还可从主工具栏中选择 Debug Tests 选项,在代码中设置断点并
在调试器中运行测试用例。

在这个示例中,我们仅练习了一条代码路径,应该添加更多测试用例,以充分地练习其他代码路径。尽管可以
为已经创建的一个测试方法添加额外的断言,但这并不是编写单元测试的最佳实践。通常的方式是让每个测试方法
仅测试一个方面。这意味着
( 理想情况下 ) 该方法中只有一个 Assert
这样做的原因是,更加细粒度的测试意味着如果测试失败,则造成失败的原因通常更加显而易见。此外,需要注
意该方法在第一个失败的
Assert 语句之后没有继续执行。如果方法中有多个断言,则更难确定造成失败的原因。虽然
如此, 方法中通常仍然有两个或三个断言,并且有一个可以传入
Assert 语句的参数,作为在测试失败时显示的消息。
10.1.1 使用特性标识测试
在进一步讨论单元测试之前,先考虑一下在 Visual Studio 2017 中如何进行测试。所有的测试用例都必须存储在
测试类中,而测试类必须位于一个测试项目中,那么到底通过什么认定方法、类或项目包含了测试用例呢?先从测
试项目开始,在底层的
XML 项目文件中,测试项目文件实际上与普通的类库项目文件之间没有任何区别。事实上,
唯一的不同之处在于项目的类型。在生成测试项目时,它会输出一个标准的
.NET 类库程序集。这里的关键区别在
于,
Visual Studio 把它看成一个测试项目,并自动分析出项目中的测试用例,对各种测试窗口进行填充。
测试过程中使用的类和方法都标记了对应的特性。测试引擎通过这些特性枚举一个程序集中的全部测试用例。
1. TestClass 特性
每个测试用例都必须位于测试类 ( 使用 TestClass 特性进行标记 ) 中。该特性仅用于把测试用例与要测试的类和成
员对应,但后面将看到使用测试类对测试用例进行分组的好处。在对
Subscription 类的测试中创建了一个
SubscriptionTest 测试类,并标记了 TestClass 特性。由于 Visual Studio 使用特性定位包含测试用例的类,因此类的名
称是不相关的。然而,采用良好的命名约定
( 如为要测试的类添加 Test 后缀 ) 将便于管理大量的测试用例。
2. TestMethod 特性
每个测试用例都被标记了 TestMethod 特性, Visual Studio 使用该特性枚举可执行的测试列表。在本例中,
SubscriptionTest 类中的 CurrentStatus_NullPaidUpToDate_TemporaryStatus 方法标记了 TestMethod 特性。同样,方法
的实际名称是不相关的,因为
Visual Studio 只使用特性来查找测试。尽管如此,在各个测试窗口列出测试用例时会
用到方法的名称,因此测试方法也应该使用有意义的名称。在查看测试结果时,这一点尤其重要。
10.1.2 其他测试特性
如前所述, Visual Studio 中的单元测试子系统是使用特性来区分测试用例的。此外,还可以使用其他各种特性
为测试用例提供更多信息。这些信息可以通过与测试用例相关的
Properties 窗口或者其他测试窗口来访问。本节介
关于单元测试需要注意一件事。简单来说,单元测试方法的默认行为是“通过”。改变此行为的
方式是向该方法添加
Assert 语句,而具体的理念是如果一条 Assert 语句失败,则单元测试就被认为已
经“失败”。然而,手动创建全新的单元测试时,其中不存在任何断言,这意味着单元测试不会开始
“失败”。为了解决此问题,在创建单元测试时会自动在其中放入
Assert.Inconclusive 语句。对于任何
测试,执行
Assert.Inconclusive 语句就意味着该测试总是会“失败”。当移除该 Assert.Inconclusive
句时,就表明测试用例已经完成。

介绍可应用于测试方法的描述性特性。
1. Description 特性
因为测试用例使用的是测试方法的名称,所以许多测试都拥有类似的名称,这些名称不足以区分测试的功能。
要解决这个问题,可使用
Description 特性,它接受一个 String 类型的参数,可用于在测试方法中提供和测试与用例
相关的其他信息。
2. Owner 特性
Owner 特性也接受一个 String 类型的参数。该特性用于指明是谁拥有、编写或者当前在使用某个测试用例。
3. Priority 特性
Priority 特性用于指定测试用例的相对优先级,它接受一个 Integer 类型的参数。尽管测试框架不使用该特性,
但是如果为测试用例指定优先级顺序,则在测试用例运行失败或者未完成时可以更有效地处理测试用例。
4. TestCategory 特性
TestCategory 特性接受一个 String 类型的参数,给测试标识一个用户定义的类别。与 Priority 特性一样,
TestCategory 特性实质上也被 Visual Studio 忽略,但可用于排序和分组相关的项。一个测试用例可属于多个类别,
但每个测试用例都必须有一个
TestCategory 特性。
5. WorkItem 特性
WorkItem 特性可在工作项跟踪系统 ( Team Foundation Server) 中把测试用例链接到一个或多个工作项上。 为测
试用例指定一个或多个
WorkItem 特性意味着在对现有功能进行修改时,可以对测试用例进行复查。相关内容详见
12 章介绍的 Team Foundation Server
6. Ignore 特性
给测试方法应用 Ignore 特性,可临时禁止运行它。带有 Ignore 特性的方法不会运行,也不会显示在测试运行的
结果列表中。
7. Timeout 特性
测试用例可能会因为各种原因而失败,例如性能测试可能要求某个功能必须在一个特定的时间段内完成。除了
通过编写复杂的多线程测试在达到该时限时终止测试用例以外, 也可以对测试用例使用
Timeout 特性和超时值 ( 以毫
秒为单位
) ,如下面的代码所示。这可以确保在抵达时限时测试用例会失败。
VB
<TestMethod()>
<Owner("Mike Minutillo")>
<Description("Tests the functionality of the Current Status Property")>
<Priority(3)>
<Timeout(10000)>
<TestCategory("Financial")>
Public Sub CurrentStatusTest()
Dim target As Subscription = New Subscription
Dim actual As Subscription.Status
actual = target.CurrentStatus
Assert.AreEqual(Subscription.Status.Temporary, actual, _
"Subscription.CurrentStatus was not set correctly.")
End Sub
C#
[TestMethod()]
[Owner("Mike Minutillo")]
可将 Ignore 特性应用于测试类,关闭该类中的所有测试方法。
[Description("Tests the functionality of the Current Status Method")]
[Priority(3)]
[Timeout(10000)]
[TestCategory("Financial")]
public void CurrentStatusTest()
{
Subscription target = new Subscription();
Subscription.Status actual;
actual = target.CurrentStatus;
Assert.AreEqual(Subscription.Status.Temporary, actual,
"Subscription.CurrentStatus was not set correctly.");
}
这段代码为原始的 CurrentStatusTest 方法使用了这些特性, 演示了这些特性的用法。 除了提供测试用例的功能和编写
者相关的额外信息外,还把该测试用例的优先级设置为
3 ,类别设置为 Financial 。最后,这段代码指定,如果测试用例
的执行时间超过
10s(10 000ms) ,就表明该测试用例失败。
10.1.3 单元测试和 Code Lens
单元测试具备一些额外的优势,超过了第 4 章所述的 Code Lens 功能。图 10-3 演示了一个单元测试的代码,在
第一次打开测试类时,这些代码会显示在代码编辑器中。
References 链接的左侧是一个菱形的蓝色小图标。该图标的工具提示表示测试尚未运行。实际上,这意味着还
没有为这个会话运行测试。
Visual Studio 的多次执行之间不会保存任何信息,表示该测试曾运行过。
执行测试后,图标会变化。它如何变化取决于测试的结果。图
10-4 是在跳过一个测试时显示的图标 ( 如执行了
Assert.Inconclusive )


图标不只是测试状态的可视化表示。当单击如图 10-5 所示的图标时,会看到测试结果的额外信息。这类似于
显示在
Test Explorer 中的信息 ( 可参见图 10-1)

在细目窗格的底部有两个额外的链接。可以使用 Run 链接在普通模式下运行测试,也可以使用 Debug 链接在
调试模式下运行测试。
当测试成功时,将显示一个绿色图标,如图
10-6 所示。测试的额外细节已经更新,但很容易再次运行或调试
测试。


Code Lens 功能属于单元测试,超出了测试类本身。图 10-7 包含了一
些代码,本章编写的测试在这些代码上运行。

代码中有两个指示器,调用特定的属性或方法时,这些指示器表示单
元测试的执行情况。
PaidUpTo 属性上面的第一个链接表明,一个单元测试
调用了
PaidUpTo 属性,该测试成功了。 CurrentStatus 属性上面的指示器表
示,两个使用
CurrentStatus 属性的单元测试中,只有一个通过了。当点击这一指示器时,会显示测试列表,包括成
功和不成功的测试,如图
10-8 所示。

10.2 指定判断条件
到目前为止,本章介绍了测试环境的结构以及测试用例是如何嵌套在测试项目的测试类中的。现在,研究一下
测试用例的结构,查看测试用例的通过或失败是如何实现的。在创建测试用例后,在测试用例的末端可以看到一条
添加的
Assert.Inconclusive 语句,指示测试尚未完成。
单元测试的设计原则是在测试开始时,系统、组件或者对象处于一个已知的状态,然后运行方法、修改属性或
者触发事件。在测试的最终阶段,需要验证系统、组件或者对象是否处于正确的状态。某些情况下,还需要验证方
法或者属性返回的结果是否正确。此时就需要指定相应的判断条件。如果条件为假,则测试系统返回该结果并结束
测试用例。条件是通过
Assert 类指定的。此外, StringAssert 类和 CollectionAssert 类分别用于在处理 String 对象和
对象集合时指定其他判断条件。
10.2.1 Assert
UnitTesting 名称空间中的 Assert ( 请不要将它与 System.Diagnostics 名称空间中的 Debug.Assert Trace.Assert
方法混淆在一起 ) 是用于对测试用例进行条件判断的主要类。其基本的断言格式如下所示。
VB
Assert.IsTrue(variableToTest, "Output message if this fails")
C#
Assert.IsTrue(variableToTest, "Output message if this fails");
第一个参数就是要测试的条件。如果条件为真,则测试用例将继续执行。否则,测试用例会输出一条消息,并
返回失败的结果。
该语句有多种重载形式,它们有的可以省略输出消息,有的可以提供
String 格式的参数。很多情况下,不是只
测试一个条件是否为真,而是要在测试用例中进行各种其他形式的测试,此时可以使用下面的这些方法:
● IsFalse :测试一个为负或者假的条件。
● AreEqual :测试两个参数是否有相同的值。
● AreSame :测试两个参数是否引用同一个对象。
● IsInstanceOfType :测试参数是不是某个特定类型的实例。
● IsNull :测试一个参数是否为空。
上面并不是完整的列表,还有其他方法,并且这些列出的方法都有相应的否定等价方法。此外,许多方法都有
多种重载方式,可通过一些不同的方式调用它们。

10.2.2 StringAssert
StringAssert 类提供的每个功能都可以通过使用 Assert 类判断一个或多个条件来实现。但是, StringAssert 类建
立的是
String 断言的条件,这不仅简化了测试用例的代码,还减少了测试某些条件所需的工作。 StringAssert 类提供
的断言包括:
● Contains :测试一个字符串中是否包含另一个字符串。
● DoesNotMatch :测试一个字符串是否不匹配一个正则表达式。
● EndsWith :测试一个字符串是否以指定的字符串结尾。
● Matches :测试一个字符串是否匹配一个正则表达式。
● StartsWith :测试一个字符串是否以指定的字符串开头。
10.2.3 CollectionAssert
类似于 StringAssert 类, CollectionAssert 类是一个用于对项集合进行断言的辅助类。例如,可以进行下面几种
断言:
● AllItemsAreNotNull :测试一个集合中的项是否没有空引用。
● AllItemsAreUnique :测试一个集合中是否有重复的项。
● Contains :测试一个集合中是否包含指定的对象。
● IsSubsetOf :测试一个集合是不是指定集合的子集。
10.2.4 ExpectedException 特性
有时,测试用例所执行的代码路径会引起异常。应尽量避免编写抛出异常的代码,但有些情况下这种处理又是
合理的。 在测试用例中, 除了在
Try-Catch 块中使用合适的断言测试是否抛出了异常外, 还可以用 ExpectedException
特性标记测试用例。例如,下面的代码修改了 CurrentStatus 属性,如果 PaidUp 的日期在订阅日期 ( 这里声明为一个
常量
) 之前,就抛出异常。
VB
Public Const SubscriptionOpenedOn As Date = #1/1/2000#
Public ReadOnly Property CurrentStatus As Status
Get
If Not Me.PaidUpTo.HasValue Then Return Status.Temporary
If Me.PaidUpTo > Now Then
Return Status.Financial
Else
If Me.PaidUpTo >= Now.AddMonths(-3) Then
Return Status.Unfinancial
ElseIf Me.PaidUpTo > SubscriptionOpenedOn Then
Return Status.Suspended
Else
Throw New ArgumentOutOfRangeException( _
"Paid up date is not valid as it is before the subscription opened.")
End If
End If
End Get
End Property
C#
public static readonly DateTime SubscriptionOpenedOn = new
DateTime(2000, 1, 1);
public Status CurrentStatus
{
get
{

if (this.PaidUpTo.HasValue == false)
return Status.Temporary;
if (this.PaidUpTo > DateTime.Today)
return Status.Financial;
else
{
if (this.PaidUpTo >= DateTime.Today.AddMonths(-3))
return Status.Unfinancial;
else if (this.PaidUpTo >= SubscriptionOpenedOn)
return Status.Suspended;
else
throw new ArgumentOutOfRangeException(
"Paid up date is not valid as it is before the subscription opened");
}
}
}
使用与之前相同的方法,可以创建一个测试该代码路径的测试用例,如下面的示例所示:
VB
<TestMethod()>
<ExpectedException(GetType(ArgumentOutOfRangeException),
"Argument exception not raised for invalid PaidUp date.")>
Public Sub CurrentStatusExceptionTest()
Dim target As Subscription = New Subscription
target.PaidUpTo = Subscription.SubscriptionOpenedOn.AddMonths(-1)
Dim expected = Subscription.Status.Temporary
Assert.AreEqual(expected, target.CurrentStatus, _
"This assertion should never actually be evaluated")
End Sub
C#
[TestMethod()]
[ExpectedException(typeof(ArgumentOutOfRangeException),
"Argument Exception not raised for invalid PaidUp date.")]
public void CurrentStatusExceptionTest()
{
Subscription target = new Subscription();
target.PaidUpTo = Subscription.SubscriptionOpenedOn.AddMonths(-1);
var expected = Subscription.Status.Temporary;
Assert.AreEqual(expected, target.CurrentStatus,
"This assertion should never actually be evaluated");
}
ExceptedException 特性不仅可以捕获由测试用例引发的每一个异常,还可以确保异常的类型匹配预期的类型。
如果测试用例没有引发任何异常,那么这个特性会导致测试失败。
10.3 初始化和清理
有时必须编写在运行测试用例时执行的大量设置代码。例如,如果单元测试使用了数据库,为了确保测试用例
可以不断重复地进行,在每一次测试完成之后,还应当把数据库恢复到初始状态。修改其他资源
( 如文件系统 ) 的单
元测试来说也是如此。在编写初始化和清理测试用例的方法时,
Visual Studio 提供了大量丰富的支持。同样,用于
初始化和清理测试用例的相应方法需要用特性进行标记。

初始化和清理测试用例的特性可分为 3 个级别:有的应用于单个测试,有的应用于整个测试类,另外一些应用
于整个测试项目。
10.3.1 TestInitialize TestCleanup 特性
顾名思义,在一个特定测试类中的每个测试用例运行之前或者结束之后,应当运行 TestInitialize TestCleanup
特性指示的方法。这些方法可分配测试类中的所有测试用例需要的资源,之后释放这些资源。
10.3.2 ClassInitialize ClassCleanup 特性
某些情况下,确保测试环境在整个测试类运行之前或者之后处于正确的状态,要比在每一次测试时设置和清理
数据简单得多。测试类可对测试用例进行有效的分组管理,现在正好验证了这一点。可以把测试用例分组存放到测
试类中,然后对每个类中的方法标记对应的
ClassInitialize ClassCleanup 特性。这些方法必须标记为 static ,标记
ClassInitialize 的方法还必须带有一个 UnitTesting.TestContext 类型的参数。
10.3.3 AssemblyInitialize AssemblyCleanup 特性
最后一个级别上的初始化和清理特性用于程序集或者项目级别。对于在整个测试项目运行之前初始化环境的方
法, 或者在整个测试项目运行结束之后执行清理操作的方法, 可以分别标记上
AssemblyInitialize AssemblyCleanup
特性。由于这些方法作用于测试项目中的每一个测试用例,因此每个测试项目中只能有一个方法可以标记上
AssemblyInitialize 或者 AssemblyCleanup 特性。与类级别上的特性一样,这些方法必须标记为 static ,用
AssemblyInitialize 标记的方法还必须带有一个 UnitTesting.TestContext 类型的参数。
对于程序集级别和类级别上的特性,即使只运行一个测试用例,也会执行标记了这些特性的方法。
10.4 测试环境
在编写测试用例时,测试引擎提供了各种辅助操作,包括管理数据集,这样就可以用大量数据运行测试用例,
并为测试用例输出各种其他信息
( 来辅助调试 ) 。可以使用在测试类中生成并传送给 AssemblyInitialize
ClassInitialize 方法的 TestContext 对象来实现这些功能。下面的代码演示了捕获 TestContext 对象值的一种方式,以
便在测试中使用它:
VB
Private Shared testContextInstance As TestContext
<ClassInitialize> _
Public Shared Sub MyClassInitialize(testContext As TestContext)
testContextInstance = testContext
End Sub
C#
private static TestContext testContextInstance;
[ClassInitialize()]
public static void MyClassInitialize(TestContext testContext)
{
testContextInstance = testContext;
}
最好将标记了 AssemblyInitialize AssemblyCleanup 特性的方法放在它们自己的测试类中,以便于查找。
如果有多个方法标记了上述两个特性,那么在运行项目中的任何测试时都会出现一个运行时错误。虽然不
会出现错误消息
( 在程序集中不能定义包含 AssemblyInitialize 特性的多个方法 ) ,但仍需要搜索
AssemblyInitialize 特性以查找不同的方法。
10.4.1 数据
10.1 一节编写的 CurrentStatus_NullPaidUpToDate_TemporaryStatus 方法只能测试通过 CurrentStatus 属性的一条
路径。为充分测试这个属性,还需要编写其他方法,每个方法都带有自己的设置和断言。然而,这种处理非常
机械,如果开发人员修改了
CurrentStatus 属性的结构,测试人员就不得不修改这些语句。为了解决这个问题,可为
CurrentStatus_NullPaidUpToDate_ TemporaryStatus 方法提供一个 DataSource 特性, 每一行数据测试通过该属性的一条
路径。要为该方法添加数据,可以遵循下面的步骤:
(1) 创建一个本地数据库文件 (.MDF 文件 ) 和数据库表来存储各种测试数据 ( 详情请参见第 26 ) 。在本例中,
创建一个名为
LoadTest 的数据库以及一个名为 Subscription_CurrentStatus
的表。 Subscription_CurrentStatus 表包含了 bigint 标识列 Id 、可为空的
datatime PaidUp ,以及 nvarchar(20) 类型的 Status 列。
(2) 在表中添加能够覆盖代码中所有路径的适当数据值。为
CurrentStatus 属性设计的测试值如图 10-9 所示。
(3) 为该测试用例添加 DataSource 特性。测试引擎使用这个特性
从指定的表中加载适当的值。然后通过
TestContext 对象将该数据提供
给测试用例。
(4) 将下面的属性添加到 test 类。该属性用于访问当前的 TextContext , 而 TextContext 则用于访问数据源中的数据。
VB
Private testContextInstance As TestContext
Public Property TestContext() As TestContext
Get
Return testContextInstance
End Get
Set(ByVal Value As TestContext)
testContextInstance = Value
End Set
End Property
C#
private TestContext testContextInstance;
public TestContext TestContext
{
get { return testContextInstance; }
set { testContextInstance = value; }
}
(5) 修改测试用例,使其从 TestContext 对象访问数据,并使用这些数据驱动测试用例。修改后的 CurrentStatus_
NullPaidUpToDate_TemporaryStatus
方法如下所示:
VB
<DataSource("System.Data.SqlClient", _
"server=.\\SQLExpress;" & _
"AttachDBFilename=|DataDirectory|\\LoadTest.mdf;" & _
"Integrated Security=True", _
"Subscription_CurrentStatus", DataAccessMethod.Sequential)> _
<TestMethod()>_
Public Sub CurrentStatus_NullPaidUpToDate_TemporaryStatus()
Dim target As Subscription = New Subscription
If Not IsDBNull(testContextInstance.DataRow.Item("PaidUp")) Then
如果使用 LocalDB 数据库或 Excel 文件,则还需要添加 DeploymentItem 特性。如果测试程序集被
部署到另一个位置上,则该特性可以确保复制该数据源。

target.PaidUpTo = CType(testContextInstance.DataRow.Item("PaidUp"), Date)
End If
Dim val As Subscription.Status = _
CType([Enum].Parse(GetType(Subscription.Status), _
CStr(testContextInstance.DataRow.Item("Status"))), Subscription.Status)
Assert.AreEqual(val, target.CurrentStatus, _
"Subscription.CurrentStatus was not set correctly.")
End Sub
C#
[DataSource("System.Data.SqlClient",
"server=.\\SQLExpress;" +
"AttachDBFilename=|DataDirectory|\\LoadTest.mdf;" +
"Integrated Security=True",
"Subscription_CurrentStatus", DataAccessMethod.Sequential)]
[TestMethod()]
public void CurrentStatus_NullPaidUpToDate_TemporaryStatus()
{
var target = new Subscription();
var date =
testContextInstance .DataRow["PaidUp"] as DateTime?;
if (date != null)
{
target.PaidUpTo = date;
}
var val = Enum.Parse(typeof(Subscription.Status),
testContextInstance .DataRow["Status"] as string);
Assert.AreEqual(val, target.CurrentStatus,
"Subscription.CurrentStatus was not set correctly.");
}
执行这个测试用例时, CurrentStatus_NullPaidUpToDate_TemporaryStatus 方法会运行 4 ( 每次使用数据库表中
的一行数据
) 。每次执行该方法时,都会从数据库表中检索一个 DataRow 对象,测试方法通过 TestContext.DataRow
属性对这些数据进行访问。如果 CurrentStatus 属性中的逻辑改变了,那么可以在 Subscription_CurrentStatus 表中添
加一行,测试已经创建的所有代码路径。
在继续介绍之前,最后看一眼应用于
CurrentStatus_NullPaidUpToDate_TemporaryStatus 方法的 DataSource 特性。
该特性有
4 个参数,前 3 个参数用于判断需要提取哪个 DataTable 。最后一个参数是 DataAccessMethod 枚举,它指定
了按什么顺序从
DataTable 返回行。默认情况下,该值为 Sequential ,但也可以把它改为 Random ,从而实现每次运
行测试时都能按照不同的顺序提取数据。如果数据代表的是最终用户的数据,并对数据的处理顺序没有任何依赖关
系,那么这种处理方式就非常重要。
数据驱动的测试不只是限于数据库表,还可通过 Excel 电子表格或逗号分隔的值 (Comma-Separated
Values
CSV) 文件来驱动。
这个示例代码假定
SQL Server Express 实例运行在 .\ SQLExpress 下。如果 SQL Server 实例的主机
名不同,就需要使用该主机名作为
DataSource 连接字符串中的服务器特性的值。另外,根据用于运行
SQL Server Visual Studio 的身份,第一次运行测试时,可能存在一些权限问题。具体而言,运行测
试时的身份必须拥有
LoadTest.mdf 文件的读写权限。运行 Visual Studio 的身份需要拥有 SQL Server 实例
的管理员权限
( 这样可以附加 LoadTest.mdf)
10.4.2 输出测试结果
编写单元测试实际上就是自动化应用程序的测试过程。因此,这些测试用例可以在生成过程中执行,甚至在远
程计算机上也可以执行。这就意味着常规的输出窗口
( 如控制台 ) 并不适合输出与测试相关的信息。显然,我们不希
望测试的相关信息与应用程序生成的调试或者跟踪信息交叉混合在一起。为此,可使用一个专门通道,输出与测试
相关的信息,把它与测试结果显示在一起。
TestContext 对象的 WriteLine 方法接受一个 String 类型的参数和一系列 String.Format 类型的参数,可以使用这
些参数输出与特定测试的结果相关的信息。例如,为
CurrentStatusDataTest 方法添加下面的代码,输出测试结果的
额外信息:
VB
testContextInstance.WriteLine("No exceptions thrown for test id {0}", _
CInt(Me.TestContext.DataRow.Item(0)))
C#
testContextInstance.WriteLine("No exceptions thrown for test id {0}",
this.TestContext.DataRow[0]);
测试运行完成后,就会显示 Test Explorer 窗口,其中列出了在测试运行过程中执行的所有测试用例及其结果。
Test Explorer 窗口如图 10-10 所示,其中列出了运行已完成 ( 已通过 ) 的单元测试。

10.5 Live Unit Testing
Visual Studio 2017 中新增了一个与单元测试相关的功能,称为 Live Unit Testing 。通过该功能开发人员可以实时
跟踪单元测试在成功或失败时对代码所产生的影响,这是在代码编辑器的环境中实现的。该功能将及早捕获测试失
败提高到了一个新级别。
Live Unit Testing 仅可用于 Visual Studio 2017 Enterprise 版本,并且仅适用于 C# Visual Basic 项目。
必须显式地启动
Live Unit Testing ,之后,可以停止或暂停它。这给开发人员提供的背后理论基础是该控件是一
个双重控件。首先,它是一个独立的进程,用于评估正在进行修改的代码,确定因代码的修改而受影响的单元测试,
并运行单元测试。虽然
Live Unit Testing 的性能良好,但这会导致在开发环境中运行其他进程。
显式地启动
Live Unit Testing 的第二个理由与重构密切相关。当对代码库进行大幅度修改后,很可能会中断一
些单元测试。假定这样做是所期望的结果,让
Live Unit Testing 进程运行并告知你中断测试并不是特别有用。因此
尽管应该使用 TestContext.WriteLine 方法捕获测试执行的细节, 但 Visual Studio 测试工具会收集输
出到标准错误和标准输出流中的所有信息,并把这些数据添加到测试结果中。

在重构时可以关闭 Live Unit Testing ,然后再次启动它,代码库就会回到一种稳定和工作的状态。
在主菜单中使用
Test | Live Unit Testing | Start 命令,启动 Live Unit Testing 。这会导致 Live Unit Testing 进程监视
单元测试。片刻之后, 代码编辑器窗口中的复选框、代码行和
X 将高亮显示 ( 这取决于单元测试覆盖的状态 ) 。图 10-11
显示了这些符号。

如果查看图 10-11 中的前 3 行代码,会看到三个不同的符号。 SubscriptionOpenedOn 的声明采用的是一个绿色
复选标记,这表示使用
SubscriptionOpenedOn 的所有测试都已成功通过。 Subscriber 的声明是一个蓝色的代码行,
这意味着对该行代码没有进行单元测试。最后,
PaidUpTo 的声明是一个位于左边的红色 X 复选标记,这意味着使
PaidUpTo 的单元测试中当前至少有一个失败了。 如果想知道已失败的单元测试的数量, 可查看 PaidUpTo Code
Lens
信息,它显示有一半的单元测试已通过。要获得更具体的相关信息,单击红色的 X ,会显示单元测试列表,如
10-12 所示。

单击显示器上的单行代码,可看到所引用的实际单元测试。
10.6 高级单元测试
前面学习了如何编写和执行单元测试。本节将继续学习如何为测试用例添加定制属性,以及如何使用同样的框
架来测试私有方法和私有属性。
10.6.1 定制属性
借助测试框架为测试方法提供的各种测试特性,可以记录与测试用例相关的信息。可以在 Properties 窗口中对
这些信息进行编辑,更新测试方法中相应的特性。有时需要指定自己的属性来驱动测试方法,这也可以使用
Properties
窗口进行设置。为此,在测试方法中添加 TestProperty 特性。例如,下面的代码为测试方法添加了两个特性,一个用
于指定任意日期,另一个用于指定期望的状态。这对于使用
Test View 窗口和 Properties 窗口进行随机测试特别方便。
VB
<TestMethod()>
<TestProperty("SpecialDate", "1/1/2008")>
<TestProperty("SpecialStatus", "Suspended")>
Public Sub SpecialCurrentStatusTest()
Dim target As New Subscription
target.PaidUpTo = CType(Me.TestContext.Properties.Item("SpecialDate"), _
Date)

Dim val As Subscription.Status = _
[Enum].Parse(GetType(Subscription.Status), _
CStr(Me.TestContext.Properties.Item("SpecialStatus")))
Assert.AreEqual(val, target.CurrentStatus, _
"Correct status not set for Paidup date {0}", target.PaidUpTo)
End Sub
C#
[TestMethod]
[TestProperty("SpecialDate", "1/1/2008")]
[TestProperty("SpecialStatus", "Suspended")]
public void SpecialCurrentStatusTest()
{
var target = new Subscription();
target.PaidUpTo = this.TestContext.Properties["SpecialDate"] as DateTime?;
var val = Enum.Parse(typeof(Subscription.Status),
this.TestContext.Properties["SpecialStatus"] as string);
Assert.AreEqual(val, target.CurrentStatus,
"Correct status not set for Paidup date {0}", target.PaidUpTo);
}
10.6.2 测试私有成员
单元测试的一个卖点是它对类内部的测试 ( 以确保它们正常工作 ) 特别有效。这里的假设是,如果每一个组件都
是独立工作的,它们在一起正常工作的可能性就非常大。而事实上,单元测试可用于测试多个类的合作运行。那么,
单元测试框架测试私有方法的效果如何呢?
.NET Framework 的一个功能是它可以反射任意一个加载到内存中的类型,执行任意一个成员 ( 无论它是私有的
还是公有的
) 。这种功能会带来一定的性能损失,由于反射调用包含了一层额外的重定向操作,因此如果不断调用,
就会对系统的运行造成很大的影响。尽管如此,对于测试来说,反射可以调用一个类的内部构造,而不需要担心这
些调用所造成的潜在性能下降。
使用反射来访问类的非公有成员还存在一个更大的缺陷:这种代码会变得非常混乱。在
Subscription 类上,为
测试做准备:返回到
CurrentStatus 属性,将它的访问权限从 public 变更为 private
返回到单元测试,修改其主体,如下所示:
VB
DeploymentItem("Subscriptions.dll")> _
Public Sub Private CurrentStatusTest()
' Arrange
Dim s = new Subscription()
s.PaidUpTo = null
' Act
Dim t = s.GetType()
Dim result As Object
Result = t.InvokeMember("CurrentStatus", BindingFlags.GetProperty |
BindingFlags.Instance |BindingFlags.Public | BindingFlags.NonPublic, null, s, null)
' Assert
Assert.IsInstanceOfType(result, GetType(Subscription.Status))
Assert.AreEqual(Subscription.Status.Temporary, Cast(result, Subscription.Status))
End Sub
C#
[TestMethod()]
[DeploymentItem("Subscriptions.dll")]
public void Private CurrentStatusTest()
{

// Arrange
Subscription s = new Subscription();
s.PaidUpTo = null;
// Act
Type t = s.GetType();
object result = t.InvokeMember("CurrentStatus", BindingFlags.GetProperty |
BindingFlags.Instance |BindingFlags.Public | BindingFlags.NonPublic, null, s, null);
// Assert
Assert.IsInstanceOfType(result, typeof(Subscription.Status));
Assert.AreEqual(Subscription.Status.Temporary, (Subscription.Status)result);
}
可以看到,上面的例子以 InvokeMember 方法的形式使用了反射。特别地,它检索类型 ( 在此为 Subscription )
然后调用
InvokeMember 来检索 CurrentStatus 属性值 (GetProperty 绑定标志 ) 。接下来,判断结果是为 Subscription.Status
类型并等于 Temporary
10.7 IntelliTest
在单元测试方面, Visual Studio 2017 引入的一个测试功能是 IntelliTest 。它是 Pex 项目的产物,多年来, Pex
目在
Microsoft Research 中一直很活跃。虽然 IntelliTest 可用在许多不同的情况下,但其优点是在单元测试覆盖率中
填补“漏洞”—— 例如旧代码完全没有单元测试时的漏洞,或者单元测试已经编写好,但没有覆盖被测试类的边界
情况时的漏洞。
为提供这个功能,
IntelliTest 会分析用户指定的、应测试的方法。对于每一个方法,应通过代码确定可以采取
的不同路径。然后设置检查路径所需的任何参数的精确值,为每个路径生成单元测试。我们的目标是创建一组单元
测试,尽可能完全涵盖代码。
要创建一组
IntelliTest ,应首先右击要测试的类,从上下文菜单中选择 Run IntelliTest 。这会检查类中的代码,
生成相应的单元测试,运行它们。为了解生成的测试,可以考虑以下方法,该方法被添加到本章前面描述的
Subscription 类中。
VB
Private subscribers = New List(Of Person)
Public Sub AddSubscriber(ByVal person As Person, paidToDate As DateTime?)
If person.Country <> "US" And person.Country <> "CAN" Then
Return
End If
Dim existingSubscriber As Person = subscribers.Where( _
Function(p) p == person).FirstOrDefault()
If existingSubscriber Is Nothing Then
Subscribers.Add(person)
End If
End Sub
C#
public void AddSubscriber(Person person, DateTime? paidToDate)
{
if (person.Country != "US" && person.Country != "CAN")
return;
var existingSubscriber = subscribers.Where(
p => p == person).FirstOrDefault();
if (existingSubscriber == null)

subscribers.Add(person);
}
输出如图 10-13 所示。

在图 10-13 中,分析了四个例程。因为其中两个已被单元测试覆盖,所以 IntelliTest 过程仅生成了两个单元测
试。在
target 旁边的列中,可以看到所提供的值作为每次运行的参数。显然,两个单元测试中的一个失败了。
在顶部的工具栏中,有一些按钮可帮助浏览单元测试和结果。下拉列表中包含了生成单元测试的每个方法。屏
幕显示只有一个方法,所以如果在执行
IntelliTest 之前选择了一个类声明,就需要从列表中选择一个不同的方法。
右边的下拉列表是一个按钮,单击它会进入单元测试的定义。默认情况下,从内存中生成、编译和运行单元测
试。解决方案中没有添加项目。但如果单击
Go to Definition 按钮,就会添加一个单元测试项目,并打开单元测试代
码文件,以供修改。此时,如果想修改生成的单元测试,就可以这样做,未来执行
IntelliTest 将保存和维护现在执
行的修改。
为了解
IntelliTest 过程因生成这些测试而进行的分析级别,考虑图 10-14 ,该图更完整显示了 person 参数值。

如图 10-15 所示是生成的单元测试的第二个视图。为了得到这个视图,在对话框中间的 Views 下拉框中选择
Events 选项。这个视图列出生成单元测试时发生的事件。如果 IntelliTest 有问题,这个事件的左边会显示一个警告
符号。图
10-15 中的第一行就包含这样一个事件。在本例中,生成过程不得不猜测如何创建 Subscription 类。当选
择该行时,右边是
IntelliTest 决定用于解决问题的方式。如果对解决方案满意,就单击 Suppress 按钮 ( 工具栏中
Warnings 的左边 ) ,禁用未来的警告。但是如果想修改创建类的方式,就单击 Fix 按钮 ( 也在工具栏中 Warnings 的左
) 。这会添加工厂代码,用于给单元测试项目创建 Subscription 类,并允许根据需要编辑它。
如果刚开始编写单元测试,或使用目前还没有被测试覆盖的旧代码,
IntelliTest 的功能就是一个有效的补
充。除了帮助生成一套全面得体的单元测试集外,
IntelliTest 还可以帮助从头开始创建自己的单元测试。但注
意,不要依赖生成的测试。虽然它们能很好地识别边界情况,但它们并不彻底。生成的测试可能无法覆盖一些
业务逻辑。所以不要把它们作为一个完整的单元测试集。相反,应把它们作为一个很好的起点,来编写自己的
更多单元测试。

10.8 小结
本章介绍了如何使用单元测试来实现对代码功能的完整测试。 Visual Studio 中的单元测试框架非常全面,既可
以管理测试用例,也可以将它们记录到文档中。
在测试框架中使用合适的数据源,可以尽量减少测试所需的重复性代码。还可以扩展该框架,测试应用程序内
部的全部构造。最后,可以利用
IntelliTest 对已有的代码创建单元测试,但可能没有必要的覆盖率。

购买地址:

https://item.jd.com/12422369.html

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/26421423/viewspace-2216543/,如需转载,请注明出处,否则将追究法律责任。

全部评论
分享计算机前沿技术和国外计算机先进技术书籍。

注册时间:2011-11-08

  • 博文量
    54
  • 访问量
    107034