Visual Studio 2017高階程式設計(第7版)

qinghuawenkang發表於2018-10-16

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 號
責任編輯 :王 軍 韓宏志
裝幀設計 :孔祥峰
責任校對 :成鳳進
責任印製 :李紅英
出版發行: 清華大學出版社
網 址:
地 址: 北京清華大學學研大廈 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 中使
用這些指令,其中的說明將會適用。可以在
上找到這個線上檔案。
本書使用前提
為高效地使用本書,需要安裝 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:// ,透過 Search 工具或書名列表查詢本書,然後在
本書的細目頁面上,單擊
Book Errata 連結。在這個頁面上可以檢視到 Wrox 編輯已提交和貼上的所有勘誤項。完整
的圖書列表還包括每本書的勘誤表,網址是
/misc-pages/booklist.shtml
p2p.wrox.com
要與作者和同行討論,請加入 p2p.wrox.com 上的 P2P 論壇。這個論壇是一個基於 Web 的系統,便於你張貼與
Wrox 圖書相關的訊息和相關技術,與其他讀者和技術使用者交流心得。該論壇提供了訂閱功能,當論壇上有新的消
息時,它可以給你傳送感興趣的論題。
Wrox 作者、編輯和其他業界專家和讀者都會到這個論壇上來探討問題。
上,有許多不同的論壇,它們不僅有助於閱讀本書,還有助於開發自己的應用程式。要
加入論壇,可以遵循下面的步驟:
(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:/// 下載。登入到站點
http:/// ,使用 Search 工具或使用書名列表就可以找到本書。接著單擊本書細目頁面上的 Download Code
接,就可以獲得所有原始碼。另外,也可掃描封底的二維碼下載資料。
下載了程式碼後,只需要用自己喜歡的解壓縮軟體對它進行解壓縮即可。另外,也可以進入

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
本章原始碼下載
透過在 網站上搜尋本書的 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 對已有的程式碼建立單元測試,但可能沒有必要的覆蓋率。

購買地址:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26421423/viewspace-2216543/,如需轉載,請註明出處,否則將追究法律責任。

相關文章