# ASP.NET MVC 單元測試系列 (7)：Visual Studio Unit Test

透過 Visual Studio 裡的整合開發環境 (IDE) 結合單元測試開發是再便利不過的了，在 Visual Studio 開發工具中已經內建一套 Visual Studio Unit Testing 框架 (Framework)，可以方便協助你開發各式單元測試或整合測試的程式，工欲善其事、必先利其器，要善用他就必須先瞭解他，否則還是會事倍功半的，本篇文章會著重在 Visual Studio Unit Test 框架的概要介紹與快速上手的注意事項。

**§ 瞭解 Visual Studio Unit Test 單元測試程式的[基本結構](http://msdn.microsoft.com/zh-tw/library/ms182517.aspx)**

在單元測試專案裡最重要的是必須引用 Microsoft.VisualStudio.QualityTools.UnitTestFramework 組件：

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/73dbe7709d636b1f3afa-image_239.png "title")

然而在撰寫單元測試專案的測試類別時，裡面有三個地方需要特別注意：

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/4d115cf1d49ba8fe8609-image_240.png "title")

編號說明：

1.  類別當匯入 Microsoft.VisualStudio.QualityTools.UnitTestFramework 命名空間
2.  每個「測試類別」都要套上 TestClass 屬性(Attribute)
3.  每個「測試方法」都要套上 TestMethod 屬性(Attribute)

備註：另外還有一個 [TestContext](http://msdn.microsoft.com/zh-tw/library/ms404699\(VS.90\).aspx) 類別可用，不過我們在單元測試的領域中較少用到這個類別，有興趣的人可以參考 《[使用 TestContext 類別](http://msdn.microsoft.com/zh-tw/library/ms404699\(VS.90\).aspx)》與《[Using TestContext in Unit Tests](https://learn.microsoft.com/en-us/archive/blogs/vstsqualitytools/using-testcontext-in-unit-tests)》文章。

我們在「測試方法」上面也都能套用許多各種不同用途的屬性 (Attribute)，這部分日後的文章裡應該會陸續提到，有興趣的人可以參考：[Microsoft.VisualStudio.TestTools.UnitTesting Namespace](http://msdn.microsoft.com/en-us/library/ms244252.aspx)

**§ 瞭解 Visual Studio Unit Test 驗證失敗的方式**

在 Visual Studio Unit Test 框架裡 (或其他大部分的單元測試框架)，都是以「引發例外」的方式來告知 Visual Studio 測試執行工具 ( Test Runner ) 何時發生驗證失敗的狀況，由此可知當一個測試方法中有多個 Assert 命令可能都會發生失敗時，只有第一個發生失敗的 Assert 命令會被顯示在測試結果中，這就是因為引發例外而跳出測試方法的緣故。

在此框架中有兩個代表「驗證失敗」的例外類別，其中一個是 [AssertFailedException](http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.assertfailedexception.aspx) 類別，用來代表驗證失敗，如下圖程式碼所示，紅框圈住的兩段的用途是完全一模一樣的：

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/c86fe5d35ed34e668e01-image_241.png "title")

其測試執行的結果都會是「失敗」的項目：

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/419aeaf55e1f0f692676-image_242.png "title")

另一個例外類別是 [AssertInconclusiveException](http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.assertinconclusiveexception.aspx)，用來代表「結果不明」或「尚未完成測試」等狀態，也算是「驗證失敗」的一種，如下圖程式碼所示，紅框圈住的兩段的用途是完全一模一樣的：

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/fb50068ce78e4bf9a285-image_243.png "title")

其測試執行的結果都會是「結果不明」的項目：

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/9db817e34f21e1e3959b-image_244.png "title")

以上這兩種就是在 Visual Studio Unit Test 框架裡所能識別的例外類型，至於其他的例外都會被當成一般的例外處理，又稱為「**非預期的例外**」，在撰寫單元測試的時候若遇到了「**非預期的例外**」並不是一個好的徵兆，因為「**非預期的例外**」會導致測試結果不容易被閱讀。

如下圖所示，當執行測試的過程中若發生了「**非預期的例外**」會導致測試結果不容易被閱讀，因為真正的例外錯誤訊息從測試結果一覽表中看不出來，必須個別點開測試結果的詳細資料才能查看，非常麻煩！

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/108bf235730bab515c42-image_245.png "title")

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/6aa9cd974b5e232c7b4c-image_246.png "title")

不過如果你的測試單元在執行的時候所發生的是預期中會發生的，又稱為「**預期的例外**」 ( Expected Exception )，那麼你可以在測試方法上套用一個 \[ExpectedException\] 屬性即可告知 Visual Studio 測試執行工具 ( Test Runner ) 不要引發該例外，並讓且讓測試方法視為驗證成功。

如下圖所示，該測試方法會執行到第一個例外時中斷，此例外以下的程式碼都不會再執行，不過由於該測試方法套用了\[ExpectedException\] 屬性，所以測試結果會標示執行成功。

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/bd74841ff17b03e00e8d-image_247.png "title")

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/c0c0db90970b456beaa8-image_248.png "title")

**§ 瞭解 Visual Studio Unit Test 負責驗證的靜態類別 ( 包含一堆負責驗證的 Helper Methods )**

在 Visual Studio Unit Test 框架裡有 3 個用來輔助驗證執行結果的靜態類別，分別說明如下：

-   [**Assert**](http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.assert.aspx) **類別**

在此靜態類別中有許多好用的靜態方法，可以用幫祝你驗證各種不同的物件比對方式，不過這類的靜態方法有個缺點就是無法比對「集合型別」的物件，例如：List 或 Array 之類的物件，這時就要使用下一個類別的幫助。

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/084a81631676f475d602-image_249.png "title") 

-   [**CollectionAssert**](http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.collectionassert.aspx) **類別**

這裡的靜態方法就是專門針對集合類型的物件進行比對，也非常實用：

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/5f17452ba4b7fb151dd9-image_250.png "title") 

-   [**StringAssert**](http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.stringassert.aspx) **類別**

最後一個 [StringAssert](http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.stringassert.aspx) 靜態類別專門針對「字串型別」的資料進行驗證，也算簡單易用啦：

![alt](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/4a3e40158fb719008922-image_251.png "title")

有了這些很基本的觀念，相信能在 Visual Studio 中自在的撰寫單元測試了。

**相關連結**

-   [Visual Studio Application Lifecycle Management 使用者入門 - 單元測試的結構](http://msdn.microsoft.com/zh-tw/library/ms182517.aspx) ( .NET 4.0 )
-   [Visual Studio Team System - 單元測試的結構](http://msdn.microsoft.com/zh-tw/library/ms182517\(VS.90\).aspx) ( .NET Framework 3.5 )
-   [Visual Studio Team System - 單元測試的結構](http://msdn.microsoft.com/zh-tw/library/ms182517\(VS.80\).aspx) ( .NET Framework 2.0 )
-   [Anatomy of a Unit Test](http://msdn.microsoft.com/en-us/library/ms182517.aspx) ( .NET Framework 4.0 )
-   [Anatomy of a Unit Test](http://msdn.microsoft.com/en-us/library/ms182517\(VS.90\).aspx) ( .NET Framework 3.5 )
-   [Structure of Unit Tests](http://msdn.microsoft.com/en-us/library/ms182517\(VS.80\).aspx) ( .NET Framework 2.0 )
-   [Visual Studio Team System - 單元測試架構](http://msdn.microsoft.com/zh-tw/library/ms243147\(VS.80\).aspx)
-   [A Unit Testing Walkthrough with Visual Studio Team Test](http://msdn.microsoft.com/en-us/library/ms379625\(VS.80\).aspx)
-   [Visual Studio Team System - Unit Testing Framework](http://msdn.microsoft.com/en-us/library/ms243147\(VS.80\).aspx)
-   [Guidelines for Test-Driven Development](http://msdn.microsoft.com/en-us/library/aa730844\(VS.80\).aspx)
-   [Microsoft.VisualStudio.TestTools.UnitTesting Namespace](http://msdn.microsoft.com/en-us/library/ms244252.aspx)
-   [使用 TestContext 類別](http://msdn.microsoft.com/zh-tw/library/ms404699\(VS.90\).aspx)
-   [Using TestContext in Unit Tests](https://learn.microsoft.com/en-us/archive/blogs/vstsqualitytools/using-testcontext-in-unit-tests)
-   [More on Unit Testing : TestContext](https://weblogs.asp.net/adilakhter/more-on-unit-testing-testcontext)
-   [Assert 成員](http://msdn.microsoft.com/zh-tw/library/microsoft.visualstudio.testtools.unittesting.assert_members\(VS.90\).aspx)
-   [CollectionAssert 成員](http://msdn.microsoft.com/zh-tw/library/microsoft.visualstudio.testtools.unittesting.collectionassert_members\(VS.90\).aspx)
-   [StringAssert 成員](http://msdn.microsoft.com/zh-tw/library/microsoft.visualstudio.testtools.unittesting.stringassert_members\(VS.90\).aspx)
