2011-04-05 71 views
1

我可能在這裏問了一個錯誤的問題,我對此持開放態度,所以我將介紹一下我正在嘗試做的事情。在動態查找所有測試程序集後,我通過msbuild項目調用mstest。我爲每個測試程序集單獨調用mstest,以便結果可以在可用時立即導入到teamcity(我的CI服務器)中,而不是在TC顯示任何進度之前等待它們全部完成。Msbuild:將一個項目組轉換爲另一個具有不同結構的項目組

問題在於,它一次只運行一次測試,並且結合慢速開銷(即使在i7 quad上,mstest每個項目需要花費3-5秒的開銷)以及許多測試,測試需要幾分鐘後跑。

使用msbuild task與BuildInParallel = true(並使用/ m參數調用),可以一次構建多個項目。

那麼我現在要做的是

  • 得到所有的列表* .Tests.dll
  • 調用ExecMsTest目標在同一項目並行,每個.dll文件

    <PropertyGroup> 
         <MsTestExePath Condition="'$(MsTestExePath)'==''">C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\MSTest.exe</MsTestExePath> 
         <MsTestSettingsPath Condition="'$(MsTestSettingsPath)'==''">Project.testsettings</MsTestSettingsPath> 
    </PropertyGroup> 
    <ItemGroup> 
         <TestAssemblies Include="**\bin\**\*.Tests.dll" /> 
    </ItemGroup> 
    
    <Target Name="RunTests"> 
         <Message Text="Found test assemblies: @(TestAssemblies)" /> 
    
         <MakeDir Directories="TestResults" /> 
    
         <MsBuild Projects="@(ProjectsToBuild)" Targets="ExecMsTest" BuildInParallel="True" /> 
    </Target> 
    
    <Target Name="ExecMsTest"> 
         <Message Text="Running tests in $(TestAssembly)" /> 
         <!-- show TC progress --> 
         <Message Text="##teamcity[progressMessage 'Running tests in $(TestAssembly).dll']" Importance="High" /> 
    
         <PropertyGroup> 
           <MsTestCommand>"$(MsTestExePath)" /testcontainer:"$(TestAssembly)" /resultsfile:"TestResults\$(TestAssembly).trx" /testsettings:"$(MsTestSettingsPath)"</MsTestCommand> 
         </PropertyGroup> 
         <!-- Message Text="Exec: $(MsTestCommand)"/--> 
         <Exec Command="$(MsTestCommand)" ContinueOnError="true" /> 
    
    <!-- import data to teamcity test results --> 
         <Message Text="##teamcity[importData type='mstest' path='TestResults\$(TestAssembly).trx']" /> 
         <Message Text="Tests complete from $(TestAssembly)" /> 
    

然而,這並不完全正確。你可以看到我的itemgroup被稱爲TestAssemblies,但是我將@(ProjectsToBuild)傳遞給mstest。這是因爲MSBuild任務需要不同格式的項目組,是這樣的:

<ItemGroup> 
      <ProjectsToBuild Include="Project.mstest.proj"> 
        <Properties>TestAssembly=Project.UI.Tests</Properties> 
      </ProjectsToBuild> 
      <ProjectsToBuild Include="Project.mstest.proj"> 
        <Properties>TestAssembly=Project.Model.Tests</Properties> 
      </ProjectsToBuild> 
    </ItemGroup> 

所以這是我的問題的癥結所在,假設我甚至問正確的事情:我怎麼轉換TestAssemblies的ItemGroup成類似於ProjectsToBuild項目組的東西?

如果不明顯,TestAssemblies中的項目名稱就是* .tests.Dll文件名,而我需要該名稱作爲該項目的內部名稱,而ProjectsToBuild項目的名稱全部爲Project .mstest.proj文件(因爲它們都調用相同的文件)。


感謝@Spider M9,這個工程:

<ItemGroup> 
      <TestAssemblies Include="**\bin\**\*.Tests.dll" /> 
    </ItemGroup> 

    <Target Name="RunTests"> 
      <Message Text="Found test assemblies: @(TestAssemblies)" /> 
      <ItemGroup> 
        <TestAssembliesToBuild Include="Project.mstest.proj"> 
          <Properties>TestAssembly=%(TestAssemblies.FileName);FullPath=%(TestAssemblies.FullPath)</Properties> 
        </TestAssembliesToBuild> 
      </ItemGroup> 

      <MakeDir Directories="TestResults" /> 

      <MsBuild Projects="@(TestAssembliesToBuild)" Targets="ExecMsTest" BuildInParallel="True" /> 
    </Target> 

運行的MSBuild單線程的,我的整個構建(包括編譯,構建應用程序和數據庫快照,部署模式的一對夫婦的數據庫是在一些單元測試中使用,然後最終運行mstest)花費了大約9分30秒。在這個變化之後,它花費了大約7米。

但是,在得到這個問題的答案之前,我試着運行一個單獨的mstest實例,看看它會改善多少,並且需要大約4分50秒(其中mstest需要稍微超過1分鐘才能運行)。缺點是我必須等到所有測試完成才能獲得結果,但考慮到從6m到1m的驚人改進,這是一個完全可以接受的平衡。

需要說明的是,唯一的區別是mstest只啓動一次,而開始十幾次,大概還有多任務的一些好處。我在Core i7-860(4個物理內核,8個邏輯內核)上運行這個程序,我懷疑內核數量會對這種改變帶來的改進程度產生很大影響。

這是我的新RunTests:

<Target Name="RunTests"> 
      <Message Text="Found test assemblies: @(TestAssemblies)" /> 

      <MakeDir Directories="TestResults" /> 

      <!-- this executes mstest once, and runs all assemblies at the same time. Faster, but no output to TC until they're all completed --> 
      <PropertyGroup> 
        <MsTestCommand>"$(MsTestExePath)" @(TestAssemblies->'/testcontainer:"%(FullPath)"', ' ') /resultsfile:"TestResults\Results.trx" /testsettings:"$(MsTestSettingsPath)"</MsTestCommand> 
      </PropertyGroup> 

      <Message Text="##teamcity[progressMessage 'Running tests']" Importance="High" /> 
      <Message Text="Exec: $(MsTestCommand)" /> 
      <Exec Command="$(MsTestCommand)" ContinueOnError="true" /> 
      <Message Text="##teamcity[importData type='mstest' path='TestResults\Results.trx']" /> 
    </Target> 

也,你需要一個testsettings與文件:<Execution parallelTestCount="0">(0表示自動檢測,默認爲1),但需要使用/m參數和/或<Msbuild BulidInParallel="true">

調用的MSBuild

回答

2

試試這個:

<ItemGroup> 
    <TestAssemblies Include="**\bin\**\*.Tests.dll" /> 
    <TestAssembliesToBuild Include="Project.mstest.proj"> 
    <Properties>TestAssembly=%(TestAssemblies.FileName)</Properties> 
    </TestAssembliesToBuild> 
</ItemGroup> 
<Message Text="'%(TestAssembliesToBuild.Properties)'" /> 
+0

這讓我在正確的軌道上。我已經將TestAssemblies定義爲全局項目組,並且TestAssembliestoBuild不能在同一個項目組中定義,但是如果它位於任務內的項目組內部,它就會工作。之後,這工作很好。 – gregmac 2011-04-06 17:34:25

相關問題