使用者本文撰寫新程式碼

是新的使用者,Visual Studio 應用程式生命週期管理 (ALM) 和 Team Foundation Server (TFS) 吗? 是您想要知道如何您和您的小組可以取得最大好處,從這些工具,以建置您的應用程式的最新版本?

然後採取步驟來逐步執行這兩章教學課程] 並遵循 Peter 和許,兩位開發人員在 Fabrikam 光纖生活在一天的幾分鐘,虛構的公司,可提供有線電視及相關的服務。 您會看到如何使用 Visual Studio 和 TFS 簽出更新程式碼,當您必須中斷時,暫停工作,要求程式碼檢閱、 簽入變更,並執行其他工作的範例。

到目前為止的故事

小組最近開始採用 Visual Studio 和 Team Foundation Server 應用程式生命週期管理 (ALM)。 這些設定他們的伺服器和用戶端機器,建立積存,規劃反覆項目,以及完成其他規劃必要開始開發的應用程式。

這一章的概觀

Peter 簡要檢閱他積存,並選取他能在今天的工作。 他,他計劃開發的程式碼的單元測試。 一般而言,他就會執行測試數次在一個小時的時間,逐漸撰寫更詳細的測試,然後撰寫程式碼,使其傳遞。 通常,他會討論他的程式碼的介面與同事會使用他寫的方法。

注意事項注意事項

本主題中討論的我的工作和程式碼涵蓋範圍功能都只適用於Visual Studio Premium和 Visual Studio Ultimate.

本主題中

  • 檢閱個人的積存,並準備開始工作的工作

  • 建立第一個單元測試

  • 建立新的程式碼 stub

  • 執行第一個測試

  • 同意 API

  • 紅、 綠,重構...

  • 程式碼涵蓋範圍

  • 何時我們完成?

  • 簽入變更

檢閱個人的積存,並準備開始工作的工作

Team 總管,Peter 開啟 我工作頁面。 小組同意在目前的 sprint,Peter 適用於評估發票狀態,在產品積存中的最高優先順序項目。 Peter 決定實作數學函式,最高優先順序積存項目的子任務的開頭。 他拖曳這項工作從可用的工作項目 列出成 中進行的工作項目 & 變更清單。

檢閱個人的積存,並準備開始工作的工作

Team Navigator 中 [我的工作] 頁面上的「待辦清單」

  1. Team 總管

    1. 如果您沒有已連接到您想要再使用中的 team 專案連接到 team 專案

    2. 選擇 首頁圖示 家用,然後選擇 [ 我的工作圖示 我工作

  2. 我的工作 頁面上,拖曳工作 可用的工作項目 清單來 中進行的工作項目一節。

    您也可以選取中的工作可用的工作項目 清單,然後選擇 [ 開始

草稿累加工作計劃

Peter 通常是開發一系列的小型的步驟中的程式碼。 每個步驟通常會採用不能超過一個小時的時間,並且會花少到十分鐘。 在每個步驟中,他會寫入新的單元測試,並變更他正在開發,以便它會傳遞新的測試,除了他所撰寫的測試的程式碼。 有時候將寫入新的測試之前變更程式碼,有時他撰寫測試之前,會在變更程式碼時。 有時候他來不及。 也就是他就可以改善程式碼而不加入新的測試。 他不會再變更測試通過,除非他決定它並未正確代表需求。

在每個小步驟的結尾,他可以執行此區域的程式碼相關的所有單元測試。 他不會考慮步驟完成直到通過每個測試。

不過,他將不會檢查程式碼到 Team Foundation Server 直到他已完成整個任務。

Peter 中寫下下列幾個小步驟概略的計劃。 他知道確切的詳細資料和後期的反覆的順序都可能會變更,看他使用。 以下是他初始的步驟清單供此特定的工作:

  1. 建立測試方法 stub — 也就是只在方法簽章。

  2. 滿足一個一般的特定情況。

  3. 測試範圍廣泛。 請確定程式碼會正確地回應大範圍的值。

  4. 負數的例外狀況。 依正常程序處理不正確的參數。

  5. 程式碼涵蓋範圍。 請確定至少 80%的程式碼會執行的單元測試。

部分同事在測試程式碼中的註解中撰寫這類的計劃。 其他人只是記其計劃。 Peter 尋找有用的工作項目 [描述] 欄位中寫入他的步驟清單。 如果他應該有暫時切換到較為緊急任務,他就會知道哪裡可以找到他時無法回到它的清單。

建立第一個單元測試

Peter 一開始先建立單元測試。 他會開頭單元測試,因為他想要撰寫使用他的新類別的程式碼範例。

這是他測試的類別程式庫的第一個單元測試,因此他建立了新的單元測試專案。 他打開新的專案 對話方塊並選擇 視覺 C#測試,然後再 單元測試專案

在 [新增專案] 對話方塊中選取的 [單元測試專案]

單元測試專案會提供他可以在其中撰寫他範例的 C# 檔案。 在這個階段,他只是要說明如何叫他的新方法的其中之一:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Fabrikam.Math.UnitTest
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        // Demonstrates how to call the method.
        public void SignatureTest()
        {
            // Create an instance:
            var math = new Fabrikam.Math.LocalMath();

            // Get a value to calculate:
            double input = 0.0;

            // Call the method:
            double actualResult = math.SquareRoot(input);

            // Use the result:
            Assert.AreEqual(0.0, actualResult);
        }
    }
}

在測試方法中,因為他已寫入他的程式碼時,他想讓範例能夠運作,他將寫入的範例。

若要建立單元測試專案和方法

通常您會建立新的測試專案,為正在測試每個專案。 如果測試專案已經存在,您只可以加入新測試方法和類別。

此程序使用 Visual Studio 的單元測試架構,但您也可以使用其他提供者的架構。 測試總管 works 同樣充分地使用其他的架構,提供您安裝適當的介面卡。

  • 如果不存在,請建立測試專案。

    • 新的專案 對話方塊方塊中,選擇一種語言,例如, Visual BasicVisual C++視覺 C#。 選擇測試 ,然後 單元測試專案
  • 將測試加入至測試類別所提供。 每個單元測試是一種方法。

    每個單元測試的字首必須TestMethod屬性和單元測試方法,應該都沒有參數。 您可以使用任何您想要的單元測試方法的名稱:

            [TestMethod]
            public void SignatureTest()
            {...}
    
        <TestMethod()>
        Public Sub SignatureTest()
        ...
        End Sub
    
  • 每個測試方法應該呼叫的方法, Assert類別,以表示它已經通過或失敗。 一般而言,您可以確認預期和實際作業的結果相等:

    Assert.AreEqual(expectedResult, actualResult);
    
    Assert.AreEqual(expectedResult, actualResult)
    
  • 您的測試方法可以呼叫沒有其他一般方法TestMethod屬性。

  • 您可以將測試組織成多個類別。 每個類別的字首必須TestClass屬性。

    [TestClass]
    public class UnitTest1
    { ... }
    
    <TestClass()>
    Public Class UnitTest1
    ...
    End Class
    

如需有關如何在 c + + 撰寫單元測試的詳細資訊,請參閱 使用適用於 C++ 的 Microsoft 單元測試架構撰寫適用於 C/C++ 的單元測試.

建立新的程式碼 stub

接下來,Peter 會為他的新程式碼中,建立類別庫專案。 現在沒有專案,以供在開發程式碼和單元測試的專案。 他將從測試專案的專案參考加入至開發的程式碼時。

包含「測試」和「類別」專案的 [方案總管]

在新的專案,他會加入新的類別和方法,至少讓測試建置成功的最小版本。 若要這麼做最快的方法是從測試中的引動過程中產生類別和方法的 stub。

        public double SquareRoot(double p)
        {
            throw new NotImplementedException();
        }

若要從測試產生的類別和方法

首先,建立您要加入新的類別,除非它已經存在的專案。

若要產生的類別

  1. 將游標置於您想要產生,例如,類別的範例 LocalMath. 在快顯功能表上選擇 [ 產生程式碼新的型別

  2. 新的型別 對話方塊中,設定 專案類別庫專案。 在這個範例中,它是 Fabrikam.Math。

若要產生的方法

  • 例如,將游標放在方法呼叫 SquareRoot. 在快顯功能表上選擇 [ 產生程式碼方法 Stub

執行第一個測試

Peter 能夠建置並執行測試,藉由按下 CTRL + R、 t。 測試結果顯示紅色的失敗指示器,並測試出現在清單的失敗測試

[單元測試總管] 中有一個測試失敗

他就會簡單的變更對程式碼中:

       public double SquareRoot(double p)
        {
            return 0.0;
        }

他一次執行測試,並將傳遞:

[單元測試總管] 中有一個測試成功

若要執行單元測試

顯示 [全部執行] 按鈕的 [測試總管]

  • 測試 ] 功能表中,選擇 執行的所有測試

    -或者-

  • 如果測試總管開啟,請選擇全部執行

    -或者-

  • 將游標放在測試程式碼檔案和按下 CTRL + R、 T

  • 如果測試出現在失敗測試

    開啟測試,例如,連按兩下名稱。

    會顯示測試失敗的點。

若要測試的完整清單,請參閱 選擇 顯示所有。 若要回復到摘要資訊,請選擇 [ 家用檢視。

若要測試結果的詳細資訊,請參閱在測試總管中選取測試。

若要巡覽至程式碼的測試, 按兩下測試總管] 中的測試,或選擇開啟測試快顯功能表上。

若要偵錯測試, 開啟一或多個測試的快顯功能表,然後選擇偵錯選取的測試

若要在背景中執行測試,每當您建置方案, 切換建置後執行的測試。 先前失敗的測試會執行第一個。

同意介面

Peter 呼叫他的同事許上 Lync,並與共用他的畫面。 她將會使用他的元件。 他會顯示他的初始範例。

許認為的範例是 [確定],但註解,"大量函式會傳遞該測試 」。

Peter 回覆,「 第一項測試是為了確定名稱和函式的參數正確。 現在我們可以撰寫擷取這個函式的主要需求的測試 」。

在一起,他們會撰寫下列測試:

  
      [TestMethod]
        public void QuickNonZero()
        {
            // Create an instance to test:
            LocalMath math = new LocalMath();

            // Create a test input and expected value:
            var expectedResult = 4.0;
            var inputValue = expectedResult * expectedResult;

            // Run the method:
            var actualResult = math.SquareRoot(inputValue);

            // Validate the result:
            var allowableError = expectedResult/1e6;
            Assert.AreEqual(expectedResult, actualResult, allowableError,
                "{0} is not within {1} of {2}", actualResult, allowableError, expectedResult);
        }

提示

這個函式,Peter 正在使用測試第一個開發,他先撰寫單元測試功能,然後再寫入滿足測試的程式碼。在其他情況下,他發現這種作法是不切實際的所以相反地,他將寫入測試之後他在寫程式碼。但他認為一定要撰寫單元測試 — 是否之前或之後的程式碼,因為它們的程式碼保持穩定。

紅、 綠,重構...

Peter 遵循週期中他重複寫入測試,並確認它就會失敗,將寫入程式碼,讓測試通過,並將 [重整 — 也就改善而不變更測試的 [程式碼。

紅色

Peter 按下 CTRL + R、 T 來執行他許以建立新的測試。 他會寫入任何測試之後,他一律會執行,以確保它失敗之前他的程式碼,讓其通過。 這是的練習,他學會之後他忘了放他有撰寫一些測試的判斷提示。 看到失敗的結果,讓他他會讓其通過,當測試結果正確表示未滿足需求的信心。

若要設定的另一個很有用的作法是建置後執行的測試。 這個選項會執行測試在背景中每次您建置方案,以便您有連續的報表,您的程式碼的測試狀態。 Peter 已在第一個可疑它可能會使 Visual Studio 太慢回應,但他發現該這很少發生。

[單元測試總管] 中有一個測試失敗

綠色

Peter 寫入他第一次的嘗試,他正在開發之方法的程式碼:

    public class LocalMath
    {
        public double SquareRoot(double x)
        {
            double estimate = x;
            double previousEstimate = -x;
            while (System.Math.Abs(estimate - previousEstimate) > estimate / 1000)
            {
                previousEstimate = estimate;
                estimate = (estimate * estimate - x) / (2 * estimate);
            }
            return estimate;
        }
        

Peter 再次執行測試,並通過所有測試:

[單元測試總管] 中有兩個測試成功

重構

現在,程式碼會執行其主要的函式,Peter 會查看程式碼以尋找方式,使其較佳,或讓它更容易在未來變更。 他發現他可以減少在迴圈中執行計算的數字:

public class LocalMath
    {
        public double SquareRoot(double x)
        {
            double estimate = x;
            double previousEstimate = -x;
            while (System.Math.Abs(estimate - previousEstimate) > estimate / 1000)
            {
                previousEstimate = estimate; 
                estimate = (estimate + x / estimate) / 2;
                //was: estimate = (estimate * estimate - x) / (2 * estimate);
            }
            return estimate;
        }

他會驗證測試仍然傳遞:

[單元測試總管] 中有兩個測試成功

提示

每一項變更時您正在開發程式碼應重整或副檔名:

  • 重構表示您不要變更測試,因為您沒有新增新的功能。

  • 副檔名表示加入測試,並進行所需通過現有和新的測試程式碼變更。

如果您要更新現有的程式碼已變更的需求,也會刪除舊的測試,不再代表目前的需求。

請避免變更已經通過測試。相反地,加入新的測試。只寫入代表真實的需求的測試。

每次變更後執行的測試。

...],重複

Peter 他一系列的副檔名] 和 [重整的步驟,就會使用繼續小步驟他清單為概略指南。 他永遠不會在每個延伸後執行重構的步驟,他有時候連續執行一個以上的重構步驟。 但是,他永遠執行單元測試每個變更後的程式碼。

有時候他加入的測試,不須變更的程式碼,但是,加入他他的程式碼正常運作的信心。 比方說,他想要確定函式適用於透過廣泛的輸入。 他會寫入多個測試,這種:

        [TestMethod]
        public void SqRtValueRange()
        {
            LocalMath math = new LocalMath();
            for (double expectedResult = 1e-8;
                expectedResult < 1e+8;
                expectedResult = expectedResult * 3.2)
            {
                VerifyOneRootValue(math, expectedResult);
            }
        }
        private void VerifyOneRootValue(LocalMath math, double expectedResult)
        {
            double input = expectedResult * expectedResult;
            double actualResult = math.SquareRoot(input);
            Assert.AreEqual(expectedResult, actualResult, expectedResult / 1e6);
        }

這項測試通過第一次執行:

[單元測試總管] 中有三個測試成功

只是要確定此結果不是犯的錯誤,請他暫時引入小錯誤他的測試,使它失敗。 之後看到失敗,他可以修正它一次。

提示

務必先測試失敗前使其通過測試。

例外狀況

Peter 現在即會移至撰寫測試例外的輸入:

[TestMethod]
        public void RootTestNegativeInput()
        {
            LocalMath math = new LocalMath();
            try
            {
                math.SquareRoot(-10.0);
            }
            catch (ArgumentOutOfRangeException)
            {
                return;
            }
            catch
            {
                Assert.Fail("Wrong exception on negative input");
                return;
            }
            Assert.Fail("No exception on negative input");
        }

這項測試會放在迴圈中的程式碼。 他必須使用取消測試總管] 中的按鈕。 這 10 秒內終止程式碼。

Peter 想要確定永無止盡的迴圈可能不會發生組建伺服器上。 雖然伺服器會在完成逾時執行,是很長的逾時,並會導致經過長時間延遲。 因此,他會在加入明確的逾時這項測試:

        [TestMethod, Timeout(1000)]
        public void RootTestNegativeInput()
        {...

明確的逾時讓失敗的測試。

Peter 然後更新程式碼來處理這種例外狀況:

       public double SquareRoot(double x)
        {
            if (x <= 0.0) 
            {
                throw new ArgumentOutOfRangeException();
            }

迴歸分析

新的測試階段,但迴歸分析。 用來傳遞測試現在就會失敗:

之前成功的「單元測試」現在卻失敗

Peter 尋找並修正錯誤:

      public double SquareRoot(double x)
        {
            if (x < 0.0)  // not <=
            {
                throw new ArgumentOutOfRangeException();
            }

問題修正後,所有測試都通過:

[單元測試總管] 中有四個測試成功

提示

請確定每個測試階段對程式碼每次變更後。

程式碼涵蓋範圍

在他的工作期間的時間間隔,並最後他檢查程式碼中之前,Peter 取得程式碼涵蓋範圍報告。 這會顯示程式碼中有多少已被他的測試執行的。

Peter 的小組是至少 80%的涵蓋範圍。 因為很難達成高的涵蓋範圍,這種類型的程式碼,它們會放鬆產生的程式碼,這項需求。

良好的涵蓋範圍不是保證測試元件的完整功能,它並不保證程式碼能夠運作的每個範圍的輸入值。 不過,是相當關閉的相互關聯的程式碼行涵蓋範圍和元件的行為空間的涵蓋範圍之間。 因此,很好的涵蓋範圍可強化其所測試的應有的行為大部分的小組的信心。

若要取得的程式碼涵蓋範圍報告,在測試 ] 功能表中,選擇 執行分析程式碼涵蓋範圍的所有測試。 然後重新執行所有測試。

[程式碼涵蓋範圍結果] 內容和「顯示色彩」按鈕

Peter 取得 86%總涵蓋範圍。 當他展開報表中的總計時,它會顯示他正在開發的程式碼具有 100%的涵蓋範圍。 這是非常令人滿意,因為重要的分數適合受測試程式碼。 未涵蓋範圍的區段實際上是在測試本身。 藉由切換顯示程式碼涵蓋範圍色彩 Peter] 按鈕,可以查看未執行的測試程式碼的哪些部份。 不過,他決定這些區段都涵蓋範圍很重要的因為它們是在測試程式碼,就只能在偵測到錯誤時才使用。

若要確認特定的測試到達程式碼的特定分支,您可以設定顯示程式碼涵蓋範圍色彩 ,然後執行單一測試,藉由使用 執行其快顯功能表上的命令。

何時我們完成?

Peter 仍會持續更新的程式碼在小步驟,直到他確信:

  • 所有可用的單元測試成功。

    在專案中非常大的單元測試的集合,它可以對等候它們所有執行的開發人員而言顯得不切實際。 相反地,專案的運作方式的閘道群組的簽入服務,所有的自動化的測試每個已簽入的擱置集之前執行合併到來源樹狀結構。 簽入會拒絕如果執行失敗。 這可讓開發人員在自己的電腦上執行最基本的單元測試,然後再繼續其他工作,而不執行中斷建置的風險。 如需詳細資訊,請參閱 使用閘道簽入建置流程來驗證變更.

  • 程式碼涵蓋範圍符合小組的標準。 75%是典型的專案需求。

  • 他的單元測試會模擬每個層面的行為,是必要的包括一般和例外的輸入。

  • 他的程式碼很容易瞭解和擴充。

所有這些條件符合時,Peter 已經準備好檢查原始檔控制他的程式碼。

程式碼的開發與單元測試的原則

Peter 時發展的程式碼套用下列原則:

  • 開發單元測試,以及程式碼,並且執行經常在開發期間。 單元測試代表您元件的規格。

  • 不要變更單元測試,除非需求已變更,或測試了錯誤。 當您擴充程式碼的功能,逐漸加入新的測試。

  • 瞄準至少 75%的測試所涵蓋的程式碼。 在時間間隔,並在簽入來源程式碼之前,請查看程式碼涵蓋範圍結果。

  • 檢查在您的單元測試,以及程式碼,以便連續或定期的伺服器建置會執行。

  • 實際情況的每一段功能撰寫單元測試第一次。 開發滿足它的程式碼之前,請執行這項操作。

簽入變更

然後再簽入他的變更,Peter 再次使用 Lync 與他的同事許共用他螢幕,讓她可以非正式的用法允許和互動式檢閱與他他已建立。 測試繼續是討論的重點,因為許是主要興趣何種程式碼執行,沒有它的運作方式。 許同意 Peter 撰寫符合其需求。

Peter 簽入所有他有所做的變更,包括測試和程式碼,並將它們與他已完成的任務關聯。 簽入佇列小組的自動化的小組建置系統來驗證他使用小組的 CI 建置建置程序的變更。 此建置程序可協助團隊中的錯誤最小化其建置和測試程式碼基底 — 在乾淨的環境與開發電腦分開 — 專案小組進行每個變更。

當建置完成時,Peter 會被通知。 在建置結果] 視窗,建置成功的他所看到的所有測試傳遞。

若要簽入變更

簽入暫止的變更

  1. 功能表列上,選擇檢視Team 總管

  2. Team 總管,選擇 家用 ,然後選擇 [ 我工作

  3. 我工作 頁面上,選擇 簽入

  4. 檢視的內容暫止的變更頁面以確定:

    • 所有相關的變更會列在包含變更

    • 所有相關的工作項目會列在相關的工作項目

  5. 指定註解 ,協助您瞭解這些變更的目的,當他們查看變更的檔案和資料夾的版本控制歷程記錄的小組。

  6. 選擇簽入

若要持續整合程式碼

如需有關如何定義一個連續整合組建程序的詳細資訊,請參閱 設定 CI 組建. 您已設定好此建置程序之後,您可以選擇通知小組建置的結果。

Peter 收到已順利建置 CI 組建的通知

CI 組建的結果

如需詳細資訊,請參閱 執行、監視和管理組建.

下一步] (暫停工作、 修正錯誤,並進行程式碼檢閱)