使用編碼招式(Coding Katas)、BDD和VS2010項目模板

來源: InfoQ  發布時間: 2010-12-20 22:47  閱讀: 2233 次  推薦: 0   原文鏈接   [收藏]  
摘要:這是Jamie Phillip探索編碼招式和行為驅動開發的第三部分,也是最后一部分。

  通過編碼招式和行為驅動開發,我受到了一些啟迪,感覺良好。然而,當我意識到如果以后我就用這種方式編寫單元測試、進行開發工作,那會相當痛苦,因為每次都要引入Eric Lee的ContextSpecification。如果我可以簡單地選定一個BDD的單元測試項目,然后項目創建后我就擁有了所有項目所需的文件,那就容易多了。稍作查詢之后,我找到了一些項目模板導出向導(Project Template Export Wizard)的參考資料,似乎這就是最適合我的解決方案。

  為了能試試這個例子,你要從Visual Studio Gallery上下載并安裝Export Template Wizard(在Gallery站點上查詢Export Template Wizard)。這是一個微軟免費的Visual Studio擴展,可以將一個現有的項目導出成項目模板。

  在我們創建第一個模板前,先看看一些已有的模板,了解一下我們可能需要什么,這對我們來說是很重要的。

安裝好Visual Studio后,它的模板位于以下目錄:

  • \VisualStudioInstallationDirectory\Common7\IDE\ItemTemplates\Language\Locale\
  • \VisualStudioInstallationDirectory\Common7\IDE\ProjectTemplates\Language\Locale\

  例如,下面這個目錄包含了英文版Visual Studio的項目模板:

  • C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ItemTemplates\CSharp\1033\

  此外,當你安裝一個模板的時候(通常通過雙擊.vsix文件——微軟Visual Studio擴展文件),它會被安裝到以下文件夾:

  • \User Documents and Settings Directory\Local Settings\Application Data\Microsoft\VisualStudio\10.0\Extensions

模板提示:

使用注冊表編輯器,查看以下鍵,你會看到所有已安裝的Visual Studio 2010擴展:

HKCU\Software\Microsoft\VisualStudio\10.0\ExtensionManager\EnabledExtensions

Visual Studio啟動時會自動更新這里的注冊項。如果我們刪除掉某個擴展(比如,刪除某個擴展的目錄),Visual Studio下次啟動時會更新注冊表中的有關項。

  你會看到,所有模板的內容都存儲在ZIP文件中,這有助于有條理地“把所有東西都放在一起”。當你檢查這些ZIP文件時,你會注意到它們至少都包含一個.vstemplate文件,可以認為這就是模板的配置文件。

  考慮到我們的目的,我們對BasicUnitTest模板中的內容有所興趣,此模板位于:

C:\Program Files\Microsoft Visual Studio 10.0\Common7

  • \IDE\ItemTemplates\CSharp\1033\BasicUnitTest.zip

  查看VS 2010中的現有模板時,會注意到在代碼文件中(比如AssemblyInfo.cs),有一些特殊的關鍵字。在下面的代碼示例中,高亮顯示的文本說明了不同的模板參數關鍵字:

 
using System;
using System.Text;
using System.Collections.Generic;
$
if$ ($targetframeworkversion$ == 3.5)using System.Linq;$endif$
$
if$ ($targetframeworkversion$ == 4.0)using System.Linq;$endif$

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace $rootnamespace$
{
[TestClass]

public class $safeitemname$

{
[TestMethod]

public void TestMethod1()
{
}
}
}

  關鍵字$rootnamespace$、$safeitemname$以及$safeprojectname$是保留的模板參數:

參數

描述

$rootnamespace$

當前項目的根命名空間。 在項目中添加新項時,此參數用來替換命名空間。

$safeprojectname$

在新建項目對話框中,用戶輸入的項目名(所有不安全的字符以及空格都會被移除)。

$safeitemname$

在添加新項對話框中,用戶輸入的名稱(所有不安全的字符以及空格都會被移除)。

  查看關聯的.vstemplate文件,我們可以看到引用代碼文件的地方在ProjectItem元素里,而且ReplaceParameters屬性的值被設置為true:

 
<TemplateContent>
...
<ProjectItem ReplaceParameters="true">UnitTest.cs</ProjectItem>

</TemplateContent>

  有了這些信息,模板向導就可以在指定文件中有效地搜索并替換所有的參數;如上例中的UnitTest.cs文件。簡單地在.vstemplate文件中增加一個CustomParameter元素,就可以使用自定義參數了:

 
<TemplateContent>
...
<CustomParameters>
<CustomParameter Name="$TemplateParameter1$" Value="SomeValue"/>
<CustomParameter Name="$TemplateParameter2$" Value="SomeOtherValue"/>

</CustomParameters>
</TemplateContent>

  有了這些知識,我們可以把那些零散的東西放到一起,創建我們的BDD單元測試模板。

  1. 首先,我們要創建一個新項目,作為我們新項目模板的基礎。根據我們的目的,最佳選項是單元測試項目:

    創建好這個項目后,我們就有了構建新模板的基礎(當然,這種方法適用于所有的項目類型,不光是單元測試項目)。

  2. 記住,制作新的項目模板時,該項目中所有的東西都會被包括進去,因此現在我們可以引入所有所需的代碼文件了(在我的例子中,是來自Eric Lee的ContextSpecification.cs):

  3. 添加所需的程序集引用作為我們項目模板的一部分,在我的例子中,我想使用MSpec程序集:

    模板提示:

    需要特別注意的是,在部署這個模板的機器上,需要安裝上相同的程序集;因此你應該把引用限制在.NET framework提供的程序集上,或者在GAC中的程序集。這或許意味著,作為你模板的一部分,你必須創建一個安裝程序,以便將某些程序集安裝到GAC 中——或者要求用戶自行安裝所需的程序集。

  4. 我們要使用適當的模板參數(先前我們查閱過的$safeprojectname$)來替換代碼文件中出現的命名空間名。同時,我在引用System.Linq的地方,放上了“版本保鏢”(譯注:只在指定版本的.NET Framework上輸出代碼塊):
     
    using System;
    using System.Text;
    using System.Collections.Generic;
    $
    if$ ($targetframeworkversion$ == 3.5)using System.Linq;$endif$$if$ ($targetframeworkversion$ == 4.0)

    using System.Linq;$endif$
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    namespace $safeprojectname$
    {
    ...
    }
  5. 由于我們將在我們的測試類中使用ContextSpecification,我們要添加一個using聲明,并使用適當的模板參數添加基類的定義(這里,我在后面加上了Context這個詞,以此我們可以將它同派生測試類區別開來):
     
    using System;
    using System.Text;
    using System.Collections.Generic;
    $
    if$ ($targetframeworkversion$ == 3.5)using System.Linq;$endif$$if$ ($targetframeworkversion$ == 4.0)

    using System.Linq;
    $endif$

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

    namespace $safeprojectname$
    {

    public class $safeitemname$Context : ContextSpecification
    {

    /// <summary>

    /// The "Given some initial context" method
    /// </summary>
    protected override void Context()
    {

    // setup your class under test
    }
    }
    ...

    }
  6. 下一步是重新定義代碼文件中的測試類,讓它繼承于我們剛剛增加的Context基類。我在這里使用的代碼,來自于本文先前描述的保齡球招式解決方案,并用合適的模板參數替換了類名和方法名。
     
    /// <summary>
    /// Summary description for $safeitemname$
    /// </summary>
    [TestClass]
    public class $safeitemname$ : $safeitemname$Context
    {

    /// <summary>

    /// The "When an event occurs" method
    /// </summary>
    protected override void BecauseOf()
    {

    //
    // TODO: Add behavior setup (Action) here

    //
    }

    /// <summary>
    /// The "then ensure some outcome" method.
    /// </summary>
    [TestMethod]
    public void TestMethod1()
    {

    //

    // TODO: Add test logic here
    //
    }
    }
  7. 對于文件AssemblyInfo.cs,我們要針對我們創建的項目,替換其中的一些引用(比如程序集的名字等等),然而這次我們可以從現存的模板“定義” 中拷貝已有的AssemblyInfo(我使用“C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ProjectTemplates\CSharp\Test\1033\TestProject.zip”)到我們的項目中。
     
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    // General Information about an assembly is controlled through the following
    // set of attributes. Change these attribute values to modify the information
    // associated with an assembly.
    [assembly: AssemblyTitle("$projectname$")]
    [assembly: AssemblyDescription(
    "")]
    [assembly: AssemblyConfiguration(
    "")]
    [assembly: AssemblyCompany(
    "$registeredorganization$")]
    [assembly: AssemblyProduct(
    "$projectname$")]
    [assembly: AssemblyCopyright(
    "Copyright ?? $registeredorganization$ $year$")]
    [assembly: AssemblyTrademark(
    "")]
    [assembly: AssemblyCulture(
    "")]

    // Setting ComVisible to false makes the types in this assembly not visible
    // to COM components. If you need to access a type in this assembly from
    // COM, set the ComVisible attribute to true on that type.
    [assembly: ComVisible(false)]
    // The following GUID is for the ID of the typelib if this project is exposed to COM
    [assembly: Guid("$guid1$")]

    // Version information for an assembly consists of the following four values:
    //
    // Major Version
    // Minor Version
    // Build Number
    // Revision
    //
    // You can specify all the values or you can default the Build and Revision Numbers
    // by using the '*' as shown below:

    [assembly: AssemblyVersion("1.0.0.0")]
    [assembly: AssemblyFileVersion(
    "1.0.0.0")]
  8. 現在我們準備運行Template Export Wizard,選擇文件->將模板導出為VSIX…:

  9. 這會打開“將模板導出為VSIX”向導對話框,在這個對話框里,我們可以選擇創建一個項目模板(從解決方案中的項目),或者創建一個新項模板(從所選項目或解決方案中的某個文件)——為了導出一個項目模板,我們選擇解決方案中唯一的項目。單擊下一步>:

  10. 在向導的下一個界面里,我們可以設置在Visual Studio的“新建項目”對話框中,如何顯示這個模板。適當填寫一些字段并單擊下一步>:

    模板提示:

    假如不填寫“圖標圖片”和“預覽圖片”這兩個字段,向導會自動幫你生成圖片,你可能會不喜歡這些圖片(看起來像代碼窗口的快照——縮小了的)。建議你創建你自己的圖片,并在這兩個字段中引用你的圖片。
    在本例中,我準備了下面這種尺寸的圖片(大小與向導生成的圖片一致):


  11. 在下一個窗口里,填寫好“產品細節”,我們就完成了所有選項。尤其需要注意模板的輸出目錄,以及對話框底下的兩個復選框。
    當你單擊完成按鈕的時候,VSIX文件會生成到輸出目錄。
    復選框“自動將模板導入Visual Studio”會指示向導是否在導出模板后安裝模板——取決于你想如何創建你的模板, 你可以酌情考慮是否勾選上這一項。眼下我讓它勾選上,因為我想馬上看到結果。
    如果你沒有記下輸出路徑,那就有必要勾選上“在資源管理器窗口中顯示輸出文件目錄”——我個人喜歡選上這一項。填寫相應的字段并單擊完成:

  12. 一旦完成這個過程,打開新建項目對話框(要么通過菜單文件->新建->項目,要么通過按下CTRL + Shift + N)并選擇Visual C#項目類型,你會找到新建的BDD Unit Test項目:

  13. 創建一個BDD Unit Test類型的項目,并打開UnitTest1.cs文件。你會發現從類名繼承的模板參數(unittest1Context and unittest1)是小寫的,在我看來這不太理想:
     
    using System;
    using System.Text;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    namespace BDDUnitTest1
    {

    public class unittest1Context : ContextSpecification
    {
    ...
    }


    /// <summary>

    /// Summary description for unittest1
    /// </summary>
    [TestClass]
    public class unittest1 : unittest1Context
    {

    ...
    }
    }
  14. 回顧一下Visual Studio擴展文件(.vsix)的格式,我們可以將項目模板導出向導生成的文件重新命名成.ZIP文件:

  15. 打開這個ZIP文件,我們會看到以下這種結構;內部的zip文件(在下面例子中是 - BddUnitTest.zip)是我們所關心的,因此在合適的位置解壓縮重命名的zip文件:

  16. 解壓縮所有的相應的ZIP文件,使用Visual Studio“以…方式打開”的功能打開.vstemplate文件(當提示編輯器類型時選擇XML(文本)編輯器):

  17. 在Visual Studio的XML編輯器中打開.vstemplate文件,你會注意到每個文件對應的ProjectItem元素的TargetFileName屬性都是小寫的,盡管實際的文件名使用的是駱駝命名法:
     
    <?xml version="1.0"?>
    <VSTemplate xmlns:xsi="http://www.w3.org/2001/XMLSchema-
    instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"Type="Project" Version="3.0.0" xmlns="http://sc

    hemas.microsoft.com/developer/vstemplate/2005">
    <TemplateData>
    <Name>BDD Unit Test</Name>
    <Description>A Test project based on Behavior Driven Development (BDD) principles</Description>
    <Icon>__Template_small.png</Icon>
    <PreviewImage>__Template_large.png</PreviewImage>
    <ProjectType>CSharp</ProjectType>
    <ProjectSubType />
    <SortOrder>1000</SortOrder>
    <DefaultName>BDDUnitTest</DefaultName>
    <ProvideDefaultName>true</ProvideDefaultName>
    <EnableLocationBrowseButton>true</EnableLocationBrowseButton>
    <LocationField>Enabled</LocationField>
    </TemplateData>
    <TemplateContent>
    <Project File="BddUnitTest.csproj" TargetFileName="BddUnitTest.csproj" ReplaceParameters="true">
    <ProjectItem
    TargetFileName
    ="contextspecification.cs"
    ReplaceParameters="true">contextspecification.cs</ProjectItem>
    <ProjectItem
    TargetFileName
    ="assemblyinfo.cs"
    ReplaceParameters="true">properties\assemblyinfo.cs</ProjectItem>
    <ProjectItem
    TargetFileName
    ="unittest1.cs"
    ReplaceParameters="true">unittest1.cs</ProjectItem>
    </Project>
    <CustomParameters />
    </TemplateContent>

    </VSTemplate>
  18. 僅僅更新下每個ProjectItem元素的TargetFileName屬性,使用實際文件名的駝峰式大小寫(沒必要更新ProjectItem元素的文本部分,因為這不會影響向導在創建項目時如何生成文件):
     
    <?xml version="1.0"?>
    <VSTemplate xmlns:xsi="http://www.w3.org/2001/XMLSchema-
    instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Type="Project" Version="3.0.0" xmlns="http://sc

    hemas.microsoft.com/developer/vstemplate/2005">
    <TemplateData>
    ...
    </TemplateData>
    <TemplateContent>
    <Project File="BddUnitTest.csproj" TargetFileName="BddUnitTest.csproj" ReplaceParameters="true">
    <ProjectItem
    TargetFileName
    ="ContextSpecification.cs"
    ReplaceParameters="true">contextspecification.cs</ProjectItem>
    <ProjectItem
    TargetFileName
    ="AssemblyInfo.cs"
    ReplaceParameters="true">properties\assemblyinfo.cs</ProjectItem>
    <ProjectItem
    TargetFileName
    ="UnitTest1.cs"
    ReplaceParameters="true">unittest1.cs</ProjectItem>
    </Project>
    <CustomParameters />
    </TemplateContent>
    </VSTemplate>
  19. 下一步,重新按照解壓縮的順序對這些文件進行壓縮,首先創建內部的ZIP文件,它包含更新過的.vstemplate文件(在這個例子中就是BddUnitTest.zip),然后把它放到屬于它的文件夾里(與ZIP文件名同名):

  20. 接著我們將其余文件壓縮至最終的ZIP文件中,這個文件是“更新過的”Visual Studio擴展文件(.vsix):

  21. 將新建的ZIP文件重新命名為最初由導出向導創建的vsix文件(這里就是BDD Unit Test.vsix):

  22. 關閉所有的Visual Studio 2010實例,轉到文件夾\User Documents and Settings Directory\Local Settings\Application Data\Microsoft\VisualStudio\10.0\Extensions,并刪除原先由導出向導創建的相關擴展所在的目錄(這里是 \User Documents and Settings Directory\Local Settings\Application Data\Microsoft\VisualStudio\10.0\Extensions\JasPWarE\BDD Unit Test):

  23. 在Windows資源管理器中,轉到新建的vsix文件(在這里是BDD Unit Test.vsix)并雙擊它,這會打開Visual Studio擴展安裝器:

  24. 單擊安裝,安裝過程就會執行并安裝更新過的模板:

  25. 一旦安裝好擴展,我們就可以啟動Visual Studio 2010,創建一個新的BDD Unit Test項目并檢查代碼文件,以此驗證我們的更新是否正常工作:
     
    using System;
    using System.Text;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools;

    using Microsoft.VisualStudio.TestTools.UnitTesting;

    namespace BDDUnitTest1
    {

    public class UnitTest1Context : ContextSpecification
    {

    ...
    }


    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>

    [TestClass]
    public class UnitTest1 : UnitTest1Context
    {
    ...

    }
    }

  雖然在最后進行清理工作的時候,有一定量的人工介入,但這有助于揭露更新已有的.vsix文件以及更改模板是多么容易。有了新的模板,創建BDD單元測試就容易多了,因為我們不用擔心是否引用了正確的程序集或,或者是否包含了適當的代碼文件。你僅需關注于編寫實際的測試本身。

  從編碼招式到行為驅動開發再到項目模板的旅程,向我們展示了各種各樣的實踐練習,我們可以用它們在不同層次上提高自己。編碼招式可以提高我們的編碼技能;行為驅動開發可以提高我們做設計和編寫單元測試的方法;項目模板可以改進我們創建代碼項目的過程。

  查看英文原文:Using Coding Katas, BDD and VS2010 Project Templates: Part 3

0
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()