[Test] 單元測試藝術(1) 基礎知識

單元測試不是軟件開發的新概念,在1970年就一直存在,屢屢被證實是最理想的方法之一。html

本系列將分紅3節:框架

  1. 單元測試基礎知識
  2. 打破依賴,使用模擬對象,樁對象,測試框架
  3. 建立優秀的單元測試

 

本節索引:函數

 

單元測試與集成測試工具

單元測試幾乎老是基於框架來寫的,由於框架能夠爲咱們提供統一的API來管理測試。單元測試

經常使用的框架有Unit Test(MS Test),NUnit(開源)測試

 

定義編碼

單元測試是一段代碼調用另外一段代碼,隨後檢驗一些假設的正確性。(單元指的是一個方法或函數)spa

集成測試是指把2個或多個互相依賴的軟件模塊做爲一組進行測試。設計

 

優秀的單元測試準則code

  1. 自動的,可重複
  2. 容易實現
  3. 持續可用
  4. 簡單
  5. 快速

 

 

測試驅動(TDD)開發

對於TDD確切的含義,有不少不一樣的觀點,有人以爲就是測試優先的開發,有人以爲意味着大量的測試,有人以爲是一種設計方法。

 

TDD的流程:

寫測試 寫代碼 重構 寫下一個測試

它顯示了TDD是增量性質的,每次一小步,最終完成高質量的軟件。(重構能夠在完成每一個測試後進行,也能夠在完成幾個測試後進行。重構是很是有價值意義的。)

 

TDD的優勢:

  1. 較高的代碼測試覆蓋率
  2. 測試是可信賴的
  3. 輔助設計,減小代碼複雜度

 

 

MS Test和NUnit

全部的測試框架都共享相同的核心特性:Test Declaration, Test Execution, and Assertions.

在.Net中通常使用特性標籤來添加額外的信息,下面就是MS Test和NUnit在特性標籤上不一樣的地方。

MS Test Attribute NUnit Attribute 用途
[TestClass] [TestFixture] 定義一個測試類,裏面能夠包含不少測試函數和初始化、銷燬函數(如下全部標籤和其餘斷言)。
[TestMethod] [Test] 定義一個獨立的測試函數。
[ClassInitialize] [TestFixtureSetUp] 定義一個測試類初始化函數,每當運行測試類中的一個或多個測試函數時,這個函數將會在測試函數被調用前被調用一次(在第一個測試函數運行前會被調用)。
[ClassCleanup] [TestFixtureTearDown] 定義一個測試類銷燬函數,每當測試類中的選中的測試函數所有運行結束後運行(在最後一個測試函數運行結束後運行)。
[TestInitialize] [SetUp] 定義測試函數初始化函數,每一個測試函數運行前都會被調用一次。
[TestCleanup] [TearDown] 定義測試函數銷燬函數,每一個測試函數執行完後都會被調用一次。
[AssemblyInitialize] -- 定義測試Assembly初始化函數,每當這個Assembly中的有測試函數被運行前,會被調用一次(在Assembly中第一個測試函數運行前會被調用)。
[AssemblyCleanup] -- 定義測試Assembly銷燬函數,當Assembly中全部測試函數運行結束後,運行一次。(在Assembly中全部測試函數運行結束後被調用)
[DescriptionAttribute] [Category] 定義標識分組。

 

第一個單元測試

安裝

對於MS Test,只要安裝VS則會自動安裝。在工具欄==測試==窗口==測試資源管理器打開。

 

對於NUnit,點擊連接,下載安裝便可。

編碼

  1. 配置對象
  2. 操做對象
  3. 斷言結果
[TestClass]
    public class BlogTests
    {
        public DbContext Db { get; set; }

        /// <summary>
        /// 每一個測試方法執行前都會執行
        /// </summary>
        [TestInitialize]
        public void Init()
        {
            //1 配置對象
            Db = new DbContext();
        }

        [TestMethod]
        public void TestAdd()
        {
            var blog = new Blog { Title = "單元測試的藝術", Content = "單元測試是一門藝術" };
            //2 操做對象
            Db.Add(blog);
            //3 斷言結果
            Assert.IsTrue(blog.Id > 0);
        }
        
        /// <summary>
        /// 每一個測試方法執行後都會執行
        /// </summary>
        [TestCleanup]
        public void Clean()
        {
            Db = null;
        }
    }

 

異常的測試

有時候,測試裏面上須要拋出異常,這是業務上的正確性。在單元測試裏,也有對應特性用來實現。如

[ExpectedException(typeof(OutOfMemoryException), AllowDerivedTypes = true)]//默認異常的子類也會不經過測試的
        [TestMethod]
        public void TestAdd()
        {
            var blog = new Blog { Title = "單元測試的藝術", Content = "單元測試是一門藝術" };
            //2 操做對象
            Db.Add(blog);
            throw new OutOfMemoryException();
            //3 斷言結果
            Assert.IsTrue(blog.Id > 0);
        }

 

忽略的測試

有時候,測試寫的有問題,代碼沒問題。咱們能夠暫時忽略該測試

        [Ignore]
        [TestMethod]
        public void TestAdd()
        {
            var blog = new Blog { Title = "單元測試的藝術", Content = "單元測試是一門藝術" };
            //2 操做對象
            Db.Add(blog);
            throw new OutOfMemoryException();
            //3 斷言結果
            Assert.IsTrue(blog.Id > 0);
        }

 

對測試分組

當咱們只想測試某一類測試的時候,也有對應的特性

        [TestCategory("change db")]
        [TestMethod]
        public void TestAdd()
        {
            var blog = new Blog { Title = "單元測試的藝術", Content = "單元測試是一門藝術" };
            //2 操做對象
            Db.Add(blog);
            //3 斷言結果
            Assert.IsTrue(blog.Id > 0);
        }

        [TestCategory("no change")]
        [TestMethod]
        public void TestRead()
        {
            //2 操做對象
            var blogs = Db.GetBlogs();
            //3 斷言結果
            Assert.IsTrue(blogs.Length > 0);
        }

運行選定的測試便可

 

測試

 

 

命名規範

SUT Kind SUT
項目 新建一個【被測項目】.Tests的測試項目
至少爲每一個被測試類新建一個【被測類名】Tests的類
方法

至少爲每一個方法名新建一個【方法名】【測試場景】【預期行爲】的方法

或者使用Test【方法名】的簡單命名

備註:SUT("system under test")表明被測系統,有些人喜歡CUT("code under test")。一般SUT。

 

本文做者:Never、C

本文連接:http://www.cnblogs.com/neverc/p/4742654.html

相關文章
相關標籤/搜索