11

コード カバレッジがしきい値を下回っている場合、TFS サービス (Hosted TFS2012) でビルドを失敗させようとしています。

http://scrumdod.blogspot.co.uk/2011/04/fail-build-if-code-coverage-is-low.htmlでソリューションをいじっています

ただし、私は TFS2012 を使用しており、非常に多くのことが変更されているようです。特に、テスト実行の構成は完全に異なり、ビルド プロセス テンプレートまたは .runsettings ファイルのいずれかで .coverage ファイルの場所と名前を取得または設定する方法がないようです。

TFS2012 または TFSService で .coverage ファイルの場所を検索 (または設定) するにはどうすればよいですか?

または、コード カバレッジがしきい値を下回っている場合にビルドを失敗させる別の方法はありますか?

4

3 に答える 3

9

これにはいくつかの手順が必要です。

  1. カスタム ビルド アクティビティを作成する
  2. アクティビティをビルド コントローラーに追加する
  3. 新しいビルド プロセス内でそのカスタム ビルド アクティビティを呼び出す
  4. 新しいビルド プロセスを使用する

1. カスタム ビルド アクティビティを作成します。

VS2012 で新しいプロジェクトを作成します (私は CodeCoverageLibrary と呼びます。次のアセンブリを参照します。

  • Microsoft.TeamFoundation.Build.Client
  • Microsoft.TeamFoundation.Client
  • Microsoft.TeamFoundation.TestManagement.Client
  • Microsoft.TeamFoundation.WorkItemTracking.Client
  • システム
  • System.Activities
  • System.Core
  • System.Xaml

次のコードを使用できます。

using System;
using System.Activities;
using System.Collections.Generic;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.TestManagement.Client;

namespace CodeCoverageLibrary
{
    [BuildActivity(HostEnvironmentOption.All)]
    public sealed class GetCodeCoverage : CodeActivity<double>
    {
        public InArgument<IBuildDetail> BuildDetail { get; set; }

        protected override double Execute(CodeActivityContext context)
        {
            var buildDetail = BuildDetail.Get(context);
            var buildCoverages = GetBuildCoverages(buildDetail.BuildServer.TeamProjectCollection.Uri,
                                                   buildDetail.TeamProject, buildDetail.Uri);
            return GetTotalCoverage(buildCoverages);
        }

        private static IEnumerable<IBuildCoverage> GetBuildCoverages(Uri uri, string projectName, Uri buildUri)
        {
            return TfsTeamProjectCollectionFactory.GetTeamProjectCollection(uri)
                                                  .GetService<ITestManagementService>()
                                                  .GetTeamProject(projectName)
                                                  .CoverageAnalysisManager.QueryBuildCoverage(buildUri.ToString(),
                                                                                              CoverageQueryFlags.Modules);
        }

        private static double GetTotalCoverage(IEnumerable<IBuildCoverage> buildCoverages)
        {
            int totalCoveredBlocks = 0, totalUncoveredBlocks = 0;
            foreach (var buildCoverage in buildCoverages)
            {
                foreach (var module in buildCoverage.Modules)
                {
                    totalCoveredBlocks += module.Statistics.BlocksCovered;
                    totalUncoveredBlocks += module.Statistics.BlocksNotCovered;
                }
            }

            return (totalCoveredBlocks == 0 && totalUncoveredBlocks == 0)
                                      ? 0.0
                                      : ((double) totalCoveredBlocks) /
                                        ((double) (totalCoveredBlocks + totalUncoveredBlocks));
        }
    }
}

プロジェクトをコンパイルし、TFS 上のバージョン管理されたパスに追加します。

2. アクティビティをビルド コントローラーに追加する

チーム エクスプローラーで、 [ビルド] > [アクション] > [ビルド コントローラーの管理 ... ] に移動します。次に、ビルド コントローラーの[プロパティ... ] をクリックします。[ カスタム アセンブリへのバージョン管理パス ]の下に、上記で使用したパスを入力します。

3. ビルド プロセス内でそのカスタム ビルド アクティビティを呼び出す

BuildProcessTemplates\DefaultTemplate.11.1.xamlを新しいファイルにコピーします。

新しい XAML ファイルの先頭を更新して、次の内容を含めます。

<Activity ...
          xmlns:ccl="clr-namespace:CodeCoverageLibrary;assembly=CodeCoverageLibrary"
          ...
          >
  <x:Members>
    ...
    <x:Property Name="CodeCoverageTolerance" Type="InArgument(x:Double)" />
  </x:Members>
  ...
  <this:Process.Metadata>
    <mtbw:ProcessParameterMetadataCollection>
      ...
      <mtbw:ProcessParameterMetadata BrowsableWhen="EditingDefinition" Category="#900 Misc" DisplayName="CodeCoverageTolerance" Description="If the overall code coverage drops below this threshold, then the build will fail. This is a number between 0 and 1." ParameterName="CodeCoverageTolerance" />
    </mtbw:ProcessParameterMetadataCollection>
  </this:Process.Metadata>

XAML ファイルの末尾を更新して、次の内容を含めます。

      <Sequence DisplayName="Code Coverage Check" mtbwt:BuildTrackingParticipant.Importance="None">
        <Sequence.Variables>
          <Variable x:TypeArguments="x:Double" Name="CodeCovered" />
        </Sequence.Variables>
        <ccl:GetCodeCoverage DisplayName="Getting Code Coverage" BuildDetail="[BuildDetail]" Result="[CodeCovered]" />
        <If Condition="[CodeCovered &lt; CodeCoverageTolerance]">
          <If.Then>
            <Sequence DisplayName="Comparing Code Coverage Against Tolerance">
              <mtbwa:SetBuildProperties DisplayName="Set TestStatus to Failed" mtbwt:BuildTrackingParticipant.Importance="Low" PropertiesToSet="TestStatus" TestStatus="[Microsoft.TeamFoundation.Build.Client.BuildPhaseStatus.Failed]" />
              <mtbwa:WriteBuildError Message="[&quot;Code Coverage of &quot; + CodeCovered.ToString(&quot;P&quot;) + &quot; is less than required &quot; + CodeCoverageTolerance.ToString(&quot;P&quot;)]" />
            </Sequence>
          </If.Then>
        </If>
      </Sequence>
    </mtbwa:AgentScope>
    <mtbwa:InvokeForReason DisplayName="Check In Gated Changes for CheckInShelveset Builds" Reason="CheckInShelveset">
      <mtbwa:CheckInGatedChanges DisplayName="Check In Gated Changes" />
    </mtbwa:InvokeForReason>
  </Sequence>
</Activity>

これを TFS にチェックインします。

4. 新しいビルド プロセスを使用する

チーム エクスプローラーで[ビルド] に移動し、ビルド定義を右クリックします。Edit Build Definition... > Processに移動します。Build process templateを展開し、 New...をクリックします。[既存の XAML ファイルを選択し、新しい XAML ファイルへのパスを入力します] をクリックします。[ OK]をクリックします。CodeCoverageToleranceが4. Miscの下に表示されるはずです。0 から 1 までの数値を入力して、目的のパーセンテージを示すことができます。

于 2013-04-24T17:09:28.733 に答える
0

RunTestsアクティビティの後にアクティビティを追加して、コードカバレッジの添付ファイルについてビルドをクエリし、.coverageファイルをマージおよび解析してビルドに合格/不合格にすることができます。

于 2013-01-29T17:18:13.967 に答える
0

上記の解決策について 1 つだけ、計算を次のように修正して、パーセンテージ値が小数点以下 2 桁まで返されるようにする必要があります。

return (totalCoveredBlocks == 0 && totalUncoveredBlocks == 0)
                                  ? 0.0
                                  : Math.Round(((double)totalCoveredBlocks) /
                                    ((double)(totalCoveredBlocks + totalUncoveredBlocks)) * 100, 2);
于 2013-07-23T04:09:32.490 に答える