本文章是由機器翻譯。

Agile C++

透過 Visual Studio 和 TFS 進行 Agile C++ 開發與測試

John Socha-Leialoha

下載代碼示例

您是致力於在 Visual C++ 中構建的應用程式的開發人員和測試人員。作為一名開發人員,如果您能夠提高工作效率,編寫較高品質的代碼,並能夠根據需要重寫代碼以改善體系結構,而不必擔心妨礙任何內容,豈不是很好?作為一名測試人員,您是否希望花更少的時間來編寫和維護測試,以便有時間進行其他測試活動?

在本文中,我將介紹我們 Microsoft 團隊構建應用程式時所使用的一些技術。

我們的團隊相當小。我們有 10 個人同時處理 3 個不同的專案。這些專案以 C# 和 C++ 編寫。C++ 代碼大多用於必須在 Windows PE(Windows 的精簡版)中運行的程式,其中 Windows PE 通常用於作業系統安裝。它還用作 Microsoft System Center Configuration Manager 任務序列的一部分,以運行無法在完整作業系統中運行的任務,例如將硬碟捕獲到虛擬硬碟 (VHD) 檔。對於小團隊而言,需要做很多的工作,因此我們需要提高工作效率。

我們的團隊使用 Visual Studio 2010 和 Team Foundation Server (TFS) 2010。我們使用 TFS 2010 來進行版本控制、工作跟蹤、持續集成、代碼覆蓋率收集和報告。

我們團隊編寫測試的時機和原因

首先,我將介紹我們團隊編寫測試的原因(答案可能與您團隊的答案有所不同)。對於我們的開發人員和測試人員,特定答案可能稍有不同,但也許不像您最初想像中那般不同。作為開發人員,以下是我的目標:

  • 無構建破壞
  • 無回歸
  • 自信地進行重構
  • 自信地修改體系結構
  • 通過測試驅動開發 (TDD) 來推動設計

當然,品質是這些目標背後的重要“原因”。實現這些目標後,開發人員的生活將比其不是開發人員時更加高效和有趣。

對於我們的測試人員,我將僅關注 Agile 測試人員的一個方面:編寫自動化測試。測試人員編寫自動化測試時,他們的目標包括無回歸、接受驅動開發以及收集和報告代碼覆蓋率。

當然,我們的測試人員所做的不僅僅是編寫自動化測試。我們的測試人員負責收集代碼覆蓋率,因為我們希望代碼覆蓋率數位包含所有測試結果,而不僅僅是單元測試結果(稍後會對此進行詳細介紹)。

在本文中,我將介紹我們團隊用以實現此處所述目標的不同工具和技術。

使用閘道簽入來消除構建破壞

過去,我們的團隊使用分支來確保測試人員始終擁有用於測試的穩定版本。但是,維護分支會產生開銷。我們擁有閘道簽入後,僅使用分支進行發佈,這是一個很好的轉變。

使用閘道簽入需要您設置構建控制項以及一個或多個構建代理。我不打算在此對該主題進行介紹,但是您可以在bit.ly/jzA8Ff中 MSDN 庫頁面上的“管理 Team Foundation Build”中找到詳細資訊。

設置並運行構建代理後,您可以通過在 Visual Studio 中執行以下步驟來創建閘道簽入的新構建定義:

  1. 在功能表列中按一下“視圖”,然後按一下“團隊資源管理器”,以確保團隊資源管理器工具視窗可見。

  2. 展開您的團隊專案,然後按右鍵“構建”。

  3. 按一下“新建構建定義”。

  4. 按一下左側的“觸發器”,然後選擇“閘道簽入”,如圖 1所示。

    圖 1 為您的新建構建定義選擇閘道簽入選項

  5. 按一下“構建預設值”,然後選擇構建控制器。

  6. 按一下“處理”,然後選擇要構建的專案。

保存該構建定義後(我們稱為“閘道簽入”),您將會在提交您的簽入後看到一個新對話方塊(請參見圖 2)。按一下“構建更改”來創建擱置集並將其提交至構建伺服器。如果沒有構建錯誤,並且通過所有單元測試,則 TFS 將為您簽入更改。否則,它會拒絕簽入。

圖 2 閘道簽入對話方塊

閘道簽入十分有用,因為其可確保您永遠不會破壞構建。它們也能確保通過所有單元測試。開發人員在簽入前,往往很容易忘記運行所有測試。但是使用閘道簽入後,這類情況將不再出現。

編寫 C++ 單元測試

現在,您已瞭解如何運行作為閘道簽入一部分的單元測試,那麼我們來看看您為本機 C++ 代碼編寫這些單元測試的一種方法。

我非常喜歡 TDD,原因如下:它能幫我關注行為,使我的設計更簡單。我也有一個測試形式的安全網,這些測試定義了行為約定。我可以重構,而不必擔心因不小心違反行為約定而引入錯誤。我也瞭解其他開發人員不會中斷他們所不知道的所需行為。

團隊中的一名開發人員有方法使用內置測試運行程式 (mstest) 來測試 C++ 代碼。他使用調用本機 C++ DLL 公開的公共函數的 C++/CLI 來編寫 Microsoft .NET Framework 單元測試。我在本部分對該方法進行了進一步的介紹,使您能夠直接產生實體生產代碼內部的本機 C++ 類。換句話說,除公共介面外,您還可以對其他內容進行測試。

解決方案是將生產代碼添加到靜態程式庫中,該靜態程式庫能連結至單元測試 DLL、生產 EXE 或 DLL 中,如圖 3所示。

圖 3 測試和生產通過靜態程式庫共用相同代碼

設置專案遵循該過程所需的步驟如下所示:首先創建靜態程式庫:

  1. 在 Visual Studio 中,依次按一下“檔”、“新建”和“專案”。
  2. 在“已安裝的範本”清單中按一下“Visual C++”(您將需要展開“其他語言”)。
  3. 按一下專案類型清單中的“Win32 專案”。
  4. 輸入專案的名稱,然後按一下“確定”。
  5. 按一下“下一步”,按一下“靜態”庫,然後按一下“完成”。

現在創建測試 DLL。設置測試專案還需要執行若干其他步驟。需要創建專案,並使其能夠訪問靜態程式庫中的代碼和標頭檔。

首先,在“解決方案資源管理器”視窗中按右鍵解決方案。按一下“添加”,然後按一下“新專案”。按一下範本清單中 Visual C++ 節點下的“測試”。鍵入專案名稱(我們的團隊在專案名稱末尾添加了“UnitTests”),然後按一下“確定”。

在解決方案資源管理器中,按右鍵新專案,然後按一下“屬性”。按一下左側樹中的“常見屬性”。按一下“添加新引用”。按一下“專案”選項卡,選擇使用靜態程式庫的專案,並按一下“確定”來取消“添加引用”對話方塊。

展開左側樹中的“配置屬性”節點,然後展開 C/C++ 節點。按一下 C/C++ 節點下的“常規”。按一下“配置”下拉式列示方塊,然後選擇“所有配置”,以確保同時更改“調試”版本和“發佈”版本。

按一下“附加 Include 庫”,然後輸入靜態程式庫的路徑,在這裡您需要將靜態程式庫名稱替換為 MyStaticLib:

$(SolutionDir)\MyStaticLib;%(AdditionalIncludeDirectories)

按一下相同屬性清單中的“公共語言運行時支援”屬性,並將其更改為“公共語言運行時支援(/clr)”。

按一下“配置屬性”下的“常規”部分,並將“TargetName”屬性更改為“$(ProjectName)”。預設情況下,所有測試專案的該屬性被設置為“DefaultTest”,但是它應為您專案的名稱。按一下“OK”(確定)。

您將需要重複此過程的第一部分,以將靜態程式庫添加到生產 EXE 或 DLL 中。

編寫您的第一個單元測試

您現在應該擁有了編寫新單元測試所需的所有資訊。您的測試方法將為採用 C++ 編寫的 .NET 方法,因此語法將與本機 C++ 稍有不同。如果您瞭解 C#,將會發現它在許多方面是 C++ 和 C# 語法的一個混合。有關詳細資訊,請參閱bit.ly/iOKbR0 上的 MSDN 庫文檔“針對 CLR 的語言功能”。

假設您要測試的類定義如下所示:

#pragma once
class MyClass {
  public:
    MyClass(void);
    ~MyClass(void);

    int SomeValue(int input);
};

現在您需要為 SomeValue 方法編寫測試以指定該方法的行為。 圖 4顯示了簡單單元測試可能的外觀,其中顯示了整個 .cpp 檔。

圖 4 簡單單元測試

#include "stdafx.h"
#include "MyClass.h"
#include <memory>
using namespace System;
using namespace Microsoft::VisualStudio::TestTools::UnitTesting;

namespace MyCodeTests {
  [TestClass]
  public ref class MyClassFixture {
    public:
      [TestMethod]
      void ShouldReturnOne_WhenSomeValue_GivenZero() {
        // Arrange
        std::unique_ptr<MyClass> pSomething(new MyClass);
 
        // Act
        int actual = pSomething->SomeValue(0);
 
        // Assert
        Assert::AreEqual<int>(1, actual);
      }
  };
}

如果您對編寫單元測試不熟悉,我將使用稱為“Arrange,Act,Assert”的模式。 “Arrange”部分設置所要測試方案的前置條件。 “Act”部分為調用您要測試的方法的地方。 “Assert”部分為您檢查方法是否按所需方式執行的地方。 我想在每部分前添加一個注釋,以增加可讀性並簡化“Act”部分的查找。

測試方法都以“TestMethod”屬性標記,如圖 4所示。 這些方法又必須包含在以“TestClass”屬性標記的類中。

請注意,測試方法中的第一行創建了本機 C++ 類的新實例。 我想使用 unique_ptr 標準 C++ 庫類來確保該實例會在測試方法結束後自動刪除。 因此您可以清楚地看到,您能夠將本機 C++ 與您的 CLI/C++ .NET 代碼混合。 當然也會存在某些限制,我將在下一部分中對此進行概述。

同樣,如果您以前沒有編寫過 .NET 測試,可以使用 Assert 類提供的很多有用方法來檢查不同的條件。 我想使用通用版本來明確我希望從結果獲得的資料類型。

請充分利用 C++/CLI 測試

如前所述,當您將本機 C++ 代碼和 C++/CLI 代碼混合時,需要注意一些限制。 這些不同是由於兩個代碼庫間記憶體管理的不同而導致的。 本機 C++ 使用 C++ 的新運算子來分配記憶體,您需要自己釋放記憶體。 分配一部分記憶體後,您的資料將始終位於同一位置。

另一方面,C++/CLI 代碼中的指標會因為該代碼從 NET Framework 繼承的垃圾收集模型而具有完全不同的行為。 您可以使用 gcnew 運算子而不是新運算子來在 C++/CLI 中創建新 .NET 物件,這將為物件返回物件控制碼,而不是指標。 控制碼基本上是指向指標的多個指標。 當垃圾收集在記憶體中移動託管物件時,它會根據新位置對控制碼進行更新。

混合託管指標和本機指標時必須非常小心。 我將介紹其中一些差異,並講述有關針對本機 C++ 物件充分利用 C++/CLI 測試的提示和技巧。

假設您要測試一個方法,其可返回指向字串的指標。 在 C++ 中,您能夠以 LPCTSTR 來表示字串指標。 但是在 C++/CLI 中,通常以“String^”來表示 .NET 字串。 類名稱後的托字型大小表示託管物件的控制碼。

以下是一個示例,說明如何測試方法調用返回的字串的值:

// Act
LPCTSTR actual = pSomething->GetString(1);
 
// Assert
Assert::AreEqual<String^>("Test", gcnew String(actual));

最後一行包含所有詳細資訊。 有一個 AreEqual 方法可接受受管字串,但是沒有針對本機 C++ 字串的相應方法。 因此,您需要使用受管字串。 AreEqual 方法的第一個參數是一個受管字串,因此儘管沒有使用 _T 或 L 將其標注為 Unicode 字串,它實際上也是一個 Unicode 字串。

String 類有一個接受 C++ 字串的構造函數,因此您可以創建一個新的受管字串,其將包含來自待測試方法的實際值,這樣 AreEqual 就可確保它們的值相同。

Assert 類有兩個極具吸引力的方法: IsNull and IsNotNull. 然而,這些方法的參數是控制碼而不是物件指標,這意味著您只能將這些方法用於受管物件。 Instead, you can use the IsTrue method, like this:

Assert::IsTrue(pSomething != nullptr, "Should not be null");

它能完成同樣的工作,但是需要使用更多的代碼。我添加了一個注釋,從而使期望在出現在測試結果視窗的消息中清晰明瞭,如圖 5所示。

圖 5 在錯誤消息中顯示附加注釋的測試結果

共用設置和拆解代碼

應將測試代碼視為生產代碼。換句話說,應重構測試和生產代碼,以簡化測試代碼的維護。在某些情況下,測試類中的所有測試方法可能擁有一些共同的設置和拆解代碼。您可以指定在每項測試前運行的方法,也可以指定在每項測試後運行的方法(您可以使用其中一種,兩種或都不使用)。

TestInitialize 屬性標記了一種將在測試類中每個測試方法前運行的方法。同樣,TestCleanup 屬性標記了一種將在測試類中每個測試方法後運行的方法。Here’s an example:

[TestInitialize]
void Initialize() {
  m_pInstance = new MyClass;
}
 
[TestCleanup]
void Cleanup() {
  delete m_pInstance;
}

MyClass *m_pInstance;

首先,請注意我針對 m_pInstance 使用了一個指向類的簡單指標。 為什麼我沒有使用 unique_ptr 來管理生存期?

同樣,答案與混合本機 C++ 和 C++/CLI 有關。 C++/CLI 中的執行個體變數是託管物件的一部分,因此它們只能是託管物件的控制碼以及指向本機物件或數值型別的指標。 您需要回到新建和刪除基礎來管理本機 C++ 實例的生存期。

使用指向執行個體變數的指標

如果您正在使用 COM,則可能會遇到這種情況,即您希望編寫如下代碼:

[TestMethod]
Void Test() {
  ...
HRESULT hr = pSomething->GetWidget(&m_pUnk);
  ...
}

IUnknown *m_pUnk;

這將無法編譯,並會產生如下錯誤消息:

無法將參數 1 從“cli::interior_ptr<Type>”轉換為“IUnknown **”

在本示例中,C++/CLI 執行個體變數網址類別型為 interior_ptr<IUnknown *>,該類型與本機 C++ 代碼不相容。 您想知道為什麼嗎? 我僅需要一個指標。

測試類為託管類,因此該類的實例可以通過垃圾收集器在記憶體中移動。 因此,如果您有指向執行個體變數的指標,則物件移動後,該指標將無效。

可以在本機調用過程中鎖定物件,如下所示:

cli::pin_ptr<IUnknown *> ppUnk = &m_pUnk;
HRESULT hr = pSomething->GetWidget(ppUnk);

第一行鎖定實例,直至變數超出範圍,這將使您可以將指向執行個體變數的指標傳遞給本機 C++,儘管變數包含在託管測試類中。

編寫可測試的代碼

在本文的開頭,我提到了編寫可測試代碼的重要性。我使用 TDD 來確保代碼具有可測試性,但是某些開發人員更喜歡在編寫代碼後編寫測試。無論怎麼做,我們都不僅要考慮單元測試,同時還要考慮整個測試堆疊,這點非常重要。

Mike Cohn 是 Agile 著名的多產作者,他繪製了測試自動化金字塔,該金字塔提供了有關測試類型的內容以及每層上應進行的測試數。開發人員應該編寫所有或大多數單元和元件測試,並可能編寫一些集成測試。有關該測試金字塔的詳細資訊,請參閱 Cohn 的博客文章“測試自動化金字塔的遺忘層”(bit.ly/eRZU2p)。

測試人員通常負責編寫接受度測試和 UI 測試。這些測試有時也稱為端到端測試或 E2E 測試。在 Cohn 的金字塔中,與其他類型測試的區域相比,UI 三角形是最小的。這意味著您需要編寫盡可能少的自動化 UI 測試。自動化 UI 測試往往非常脆弱,且編寫和維護成本較高。對 UI 所做的細小更改極易破壞 UI 測試。

如果您的代碼沒有編寫為可測試代碼,則您將可以輕鬆得到倒金字塔,其中大部分自動化測試為 UI 測試。這是一種很不好的情況,但底線是開發人員需確保測試人員可以在 UI 下編寫集成和接受度測試。

此外,無論出於什麼原因,我遇到的大部分測試人員都非常熟悉以 C# 編寫測試,而回避以 C++ 編寫測試。因此,我們的團隊需要在測試和自動化測試下的 C++ 代碼之間架起一個橋樑。橋樑採用裝置形式,這些裝置為 C++/CLI 類,它們像任何其他管理類一樣呈現給 C# 代碼。

構建 C# 到 C++ 裝置

此處使用的技術與我在編寫 C++/CLI 測試仲介紹的並沒有太大區別。所有這些技術均使用相同類型的混合模式代碼。區別在於它們最終的用法。

第一步是創建新專案,該專案將包含您的裝置:

  1. 在解決方案資源管理器中,按右鍵解決方案節點,按一下“添加”,然後按一下“新專案”。
  2. 在其他語言、Visual C++ 和 CLR 下,按一下“類庫”。
  3. 輸入要勇於該專案的名稱,然後按一下“確定”。
  4. 重複以上步驟以創建測試專案,從而添加引用和 include 檔。

裝置類本身與測試類有些類似,但是不具有各種屬性(請參閱圖 6)。

圖 6 C# 到 C++ 測試裝置

#include "stdafx.h"
#include "MyClass.h"
using namespace System;
 
namespace MyCodeFixtures {
  public ref class MyCodeFixture {
    public:
      MyCodeFixture() {
        m_pInstance = new MyClass;
      }
 
      ~MyCodeFixture() {
        delete m_pInstance;
      }
 
      !MyCodeFixture() {
        delete m_pInstance;
      }
 
      int DoSomething(int val) {
        return m_pInstance->SomeValue(val);
      }
 
      MyClass *m_pInstance;
  };
}

請注意,沒有標頭檔! 這是我最喜歡的 C++/CLI 功能之一。 因為該類庫構建了託管程式集,並且有關類的資訊存儲為 .NET 類型的資訊,因此您不需要標頭檔。

該類也包含了析構函數和終端子。 此處的析構函數並不是真正的析構函數。 而在 IDisposable 介面中,編譯器會將析構函數重新編寫為 Dispose 方法的實現。 因此,任何擁有析構函數的 C++/CLI 類都會實現 IDisposable 介面。

!MyCodeFixture 方法為終端子,垃圾收集器決定釋放該物件時會調用該方法,除非您之前已調用 Dispose 方法。 您既可以採用 using 語句來控制嵌入式本機 C++ 物件的生存期,也可以讓垃圾收集器來處理生存期。 有關此行為的詳細資訊,請訪問bit.ly/kW8knr 上的 MSDN 庫文章“析構函數語義更改”。

擁有 C++/CLI 裝置類後即可編寫類似圖 7 的 C# 單元測試。

圖 7 C# 單元測試系統

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MyCodeFixtures;
 
namespace MyCodeTests2 {
  [TestClass]
  public class UnitTest1 {
    [TestMethod]
    public void TestMethod1() {
      // Arrange
      using (MyCodeFixture fixture = new MyCodeFixture()) {
        // Act
        int result = fixture.DoSomething(1);
 
        // Assert
        Assert.AreEqual<int>(1, result);
      }
    }
  }
}

我想使用 using 語句來明確控制裝置物件的生存期,而不是依賴垃圾收集器。 這在測試方法中尤為重要,它能確保測試不與其他測試交互。

捕獲和報告代碼覆蓋率

我在本文開頭處介紹的最後一部分為代碼覆蓋率。 我們團隊的目標是使代碼覆蓋率能自動被構建伺服器捕獲,能發佈至 TFS 且易於獲取。

第一步是瞭解如何從運行的測試中捕獲 C++ 代碼覆蓋率。 在 Web 上搜索時,我找到了 Emil Gustafsson 的一篇資訊豐富的博客文章,標題為“使用 Visual Studio 2008 Team System 的本機 C++ 代碼覆蓋率報告”(bit.ly/eJ5cqv)。 此文章顯示了捕獲代碼覆蓋率資訊所需的步驟。 我將其轉換為 CMD 檔,這樣就可以隨時在我的開發電腦上運行該檔,以捕獲代碼覆蓋率資訊:

"%VSINSTALLDIR%\Team Tools\Performance Tools\vsinstr.exe" Tests.dll /COVERAGE
"%VSINSTALLDIR%\Team Tools\Performance Tools\vsperfcmd.exe" /START:COVERAGE /WaitStart /OUTPUT:coverage
mstest /testcontainer:Tests.dll /resultsfile:Results.trx
"%VSINSTALLDIR%\Team Tools\Performance Tools\vsperfcmd.exe" /SHUTDOWN

您將需要用包含測試的 DLL 實際名稱替換 Tests.dll。還需要準備要檢測的 DLL:

  1. 在解決方案資源管理器視窗中,按右鍵測試專案。
  2. 按一下“屬性”。
  3. 選擇“調試配置”。
  4. 展開“配置屬性”,然後展開“連結器”並按一下“高級”。
  5. 將“設定檔”屬性更改為“是(/PROFILE)”。
  6. 按一下“OK”(確定)。

這些步驟啟用了分析,您需要啟用該功能以實現程式集,從而捕獲代碼覆蓋率資訊。

重構您的專案並運行 CMD 檔。這將創建一個覆蓋率檔。將該覆蓋率檔載入至 Visual Studio,以確保可以從測試中捕獲代碼覆蓋率。

在構建伺服器上執行這些步驟並將結果發佈至 TFS 需要一個自訂構建範本。TFS 構建範本存儲在版本控制中,並且它們屬於特定團隊專案。您將在每個團隊專案下找到名為“BuildProcessTemplates”的資料夾,該資料夾很可能擁有多個構建範本。

若要使用下載中包含的自訂構建範本,請打開“原始程式碼控制資源管理器”視窗。導航到團隊專案中的“BuildProcessTemplates”資料夾,並確保已將其映射到您電腦的一個目錄。將 BuildCCTemplate.xaml 檔複製到該映射位置。將該範本添加至原始程式碼控制並將其簽入。

必須先將範本檔簽入,這樣才可在構建定義時使用這些檔。

現在您已簽入構建範本,可以創建構建定義來運行代碼覆蓋率。可以使用 vsperfmd 命令來收集 C++ 代碼覆蓋率,如前所示。Vsperfmd 會偵聽所有檢測的可執行檔的代碼覆蓋率資訊,這些可執行檔會隨著 Vsperfmd 的運行而運行。因此,您不希望其他的檢測測試同時運行。您也應該確保僅有一個構建代理在電腦上運行,該構建代理將處理這些代碼覆蓋率的運行。

我創建了一個會在夜間運行的構建定義。您可以通過以下步驟達到這一目的:

  1. 在“團隊資源管理器”視窗中,展開您團隊專案的節點。
  2. 按右鍵“構建”,其為您團隊專案下的一個節點。
  3. 按一下“新建構建定義”。
  4. 在“觸發器”部分,按一下“計畫”並選擇要運行代碼覆蓋率的時間。
  5. 在“處理”部分,按一下調用頂部構建過程範本部分中的“顯示詳細資訊”,然後選擇簽入到原始程式碼控制中的構建範本。
  6. 填寫其他必填部分並保存。

添加測試設置檔

構建定義也需要測試設置檔。其為 XML 檔,其中列出了要為其捕獲併發布結果的 DLL。以下是為代碼覆蓋率設置該檔的步驟:

  1. 按兩下 Local.testsettings 檔,然後打開“測試設置”對話方塊。
  2. 按一下左側清單中的“資料”和“診斷”。
  3. 按一下“代碼覆蓋率”並選中核取方塊。
  4. 按一下清單上的“配置”按鈕。
  5. 選中包含您的測試(也包含測試所測試的代碼)的 DLL 旁的框。
  6. 取消選中準備就緒的檢測程式集,因為構建定義將處理該問題。
  7. 按一下“確定”和“應用”,然後按一下“關閉”。

如果您想構建多個解決方案或者有多個測試專案,則您將需要複製一個測試設置檔,其包含應監視其代碼覆蓋率的所有程式集的名稱。

若要完成此任務,請將測試設置檔複製到您分支的根目錄下,並給定一個描述性名稱,如 CC.testsettings。編輯 XML。檔將至少包含來自上述步驟中的一個 CodeCoverageItem 元素。您需要為要捕獲的每個 DLL 添加一個條目。請注意,路徑與專案檔案的位置而不是測試設置檔的位置相關。將該檔簽入原始程式碼控制中。

最後,您需要修改構建定義來使用以下測試設置檔:

  1. 在“團隊資源管理器”視窗中,展開您團隊專案的節點,然後展開“構建”。
  2. 按兩下之前創建的構建定義。
  3. 按一下“編輯構建定義”。
  4. 在“處理”部分,展開“自動化測試”,然後展開 1。測試程式集並按一下“TestSettings”檔。按一下“…”按鈕,然後選擇我們之前創建的測試設置檔。
  5. Save your changes.

您可以通過按右鍵並選擇“排隊新構建”來測試該構建定義,從而立即啟動新構建。

報告代碼覆蓋率

我創建了自訂 SQL Server Reporting Services 報告,其顯示了代碼覆蓋率,如圖 8所示(我模糊了實際專案的名稱以防止犯錯)。該報告使用 SQL 查詢來讀取 TFS 倉庫中的資料,並顯示 C++ 和 C# 代碼的組合結果。

圖 8 代碼覆蓋率報告

在此我將不詳述此報告的工作方式,但是我想提醒您注意幾個方面。出於以下兩個原因,資料庫包含了來自 C++ 代碼覆蓋率的太多資訊:測試方法代碼包括在結果中,標準 C++ 庫(在標頭檔中)包括在結果中。

我將代碼添加至 SQL 查詢,其將篩選出此額外資料。如果您看一下報告中的 SQL,就會發現這一點:

    and CodeElementName not like 'std::%'
    and CodeElementName not like 'stdext::%'
    and CodeElementName not like '`anonymous namespace'':%'
    and CodeElementName not like '_bstr_t%'
    and CodeElementName not like '_com_error%'
    and CodeElementName not like '%Tests::%'

這些行排除了特定命名空間(std、stdext 和匿名)的代碼覆蓋率結果、Visual C++ 附帶的一些類(_bstr_t 和 _com_error)以及以“Tests”結尾的命名空間中的任何代碼。

後者排除了以“Tests”結尾的命名空間,從而排除了測試類中的所有方法。 創建新測試專案時,因為專案名稱以“Tests”結尾,因此,預設情況下所有測試類都位於以“Tests”結尾的命名空間中。 您可以在此處添加您希望排除的其他類或命名空間。

我只是簡要介紹了您可以進行的操作 - 請隨時跟進我的博客進度,網址為blogs.msdn.com/b/jsocha

John Socha-Leialoha 是 Microsoft 管理平臺和服務提供小組中的開發人員。他過去的成就包括編寫 Norton Commander(在 C 和裝配器中)以及編寫《Peter Norton 的組合語言書》(Brady,1987)。

衷心感謝以下技術專家對本文的審閱: Rong Lu