次の方法で共有


Devops 開発者の一日: ユーザー ストーリーの新しいコードを記述する

Azure DevOps Services |Azure DevOps Server |Azure DevOps Server 2022 |Azure DevOps Server 2020

Visual Studio 2019 |Visual Studio 2022

このチュートリアルでは、チームとチームが最新バージョンの Team Foundation Version Control (TFVC) と Visual Studio を最大限に活用してアプリをビルドする方法について説明します。 このチュートリアルでは、Visual Studio と TFVC を使用して、コードのチェックアウトと更新、中断時の作業の中断、コード レビューの要求、変更のチェックイン、その他のタスクの実行を行う方法の例を示します。

チームが Visual Studio と TFVC を採用してコードを管理すると、サーバーとクライアント コンピューターを設定し、バックログを作成し、イテレーションを計画し、アプリの開発を開始するために必要なその他の計画を完了します。

開発者はバックログを確認して、作業するタスクを選択します。 開発する予定のコードの単体テストを記述します。 通常、1 時間に数回テストを実行し、徐々に詳細なテストを記述し、合格させるコードを記述します。 開発者は、多くの場合、自分が記述しているメソッドを使用する同僚とコード インターフェイスについて話し合います。

Visual Studio のマイ ワーク および コード レビュー ツールは、開発者が作業を管理したり、同僚と共同作業したりするのに役立ちます。

Visual Studio のマイ ワークコード レビュー の機能は、次のエディションで利用できます。

  • Visual Studio 2022: Visual Studio Community、Visual Studio Professional、Visual Studio Enterprise
  • Visual Studio 2019: Visual Studio Professional と Visual Studio Enterprise

作業項目を確認し、作業を開始する準備をする

チームは、現在のスプリント中に、製品バックログの最優先事項である 請求書の状態の評価に取り組むことに同意しました。 最初に、最も優先度の高いバックログ項目の子タスクである 数学関数を実装します。

Visual Studio チーム エクスプローラーの [ マイ ワーク ] ページで、このタスクを [利用可能な作業項目] リストから [進行中の作業 ] リストにドラッグします。

バックログを確認し、作業を開始するためのタスクを準備するには

[マイ ワーク] ページのスクリーンショット。

  1. チーム エクスプローラーで、作業するプロジェクトにまだ接続していない場合は、プロジェクトに接続します

  2. [ホーム] ページで、[マイ ワーク] を選択します。

  3. [ マイワーク] ページで、[ 利用可能な作業項目] リストから [ 進行中の作業] セクションにタスクをドラッグします。

    [ 利用可能な作業項目 ] ボックスの一覧でタスクを選択し、[ 開始] を選択することもできます。

増分作業計画の下書き

一連の小さな手順でコードを開発します。 各ステップは通常、1 時間以上かからず、10 分ほどかかる場合があります。 各手順では、新しい単体テストを記述し、既に記述したテストに加えて、新しいテストに合格するように開発中のコードを変更します。 コードを変更する前に新しいテストを記述したり、テストを記述する前にコードを変更したりすることがあります。 リファクタリングする場合があります。 つまり、新しいテストを追加せずにコードを改善するだけです。 要件を正しく表していないと判断した場合を除き、合格したテストは変更しません。

すべての小さな手順の最後に、コードのこの領域に関連するすべての単体テストを実行します。 すべてのテストに合格するまで、この手順は完了とは見なされません。

タスク全体を完了するまで、コードを Azure DevOps Server にチェックインしません。

この一連の小さな手順の大まかな計画を書き留めることができます。 作業の際に、後の詳細と順序が変更される可能性があることをご存知です。 この特定のタスクの手順の最初の一覧を次に示します。

  1. テスト メソッドスタブを作成します。つまり、メソッドのシグネチャのみを作成します。
  2. 1 つの特定の一般的なケースを満たす。
  3. 幅広い範囲をテストします。 コードが大きな範囲の値に正しく応答することを確認します。
  4. 負の場合の例外。 正しくないパラメーターを適切に処理します。
  5. コード カバレッジ。 単体テストでは、少なくとも 80% のコードが実行されていることを確認します。

一部の開発者は、テスト コードのコメントにこの種のプランを記述します。 他の人は自分の計画を覚えるだけです。 タスク作業項目の [説明 ] フィールドにステップの一覧を記述すると便利です。 より緊急なタスクに一時的に切り替える必要がある場合は、リストに戻ることができるときにリストを検索する場所がわかります。

最初の単体テストを作成する

最初に単体テストを作成します。 新しいクラスを使用するコードの例を記述するため、単体テストから始めます。

これは、テストするクラス ライブラリの最初の単体テストであるため、新しい単体テスト プロジェクトを作成します。

  1. [ファイル]>[新しいプロジェクト] の順に選択します。
  2. [ 新しいプロジェクトの作成 ] ダイアログ ボックスで、[ すべての言語 ] の横にある矢印を選択し、[ C#] を選択し、[ すべてのプロジェクトの種類 ] の横にある矢印を選択し、[ テスト] を選択してから、[ MSTest Test Project] を選択します。
  3. [ 次へ] を選択し、[ 作成] を選択します。

[新しいプロジェクトの作成] ダイアログ ボックスで選択されている単体テストのスクリーンショット。

コード エディターで、 UnitTest1.cs の内容を次のコードに置き換えます。 この段階では、新しいメソッドの 1 つがどのように呼び出されるかを説明するだけです。

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 単体テスト フレームワークを使用しますが、他のプロバイダーのフレームワークを使用することもできます。 テスト エクスプローラーは、適切なアダプターをインストールすれば、他のフレームワークと同様に機能します。

  1. 前の手順を使用してテスト プロジェクトを作成します。 C#F#Visual Basic などの言語を選択できます。

  2. 提供されているテスト クラスにテストを追加します。 各単体テストは 1 つの方法です。

    • 各単体テストには 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 Unit Testing Framework を使用した C/C++ の単体テストの記述」を参照してください。

新しいコードのスタブを作成する

次に、新しいコードのクラス ライブラリ プロジェクトを作成します。 現在、開発中のコード用のプロジェクトと単体テスト用のプロジェクトがあります。 テスト プロジェクトから開発中のコードにプロジェクト参照を追加します。

テスト プロジェクトとクラス プロジェクトを含むソリューション エクスプローラーのスクリーンショット。

新しいプロジェクトでは、少なくともテストが正常にビルドできるようにする新しいクラスと最小バージョンのメソッドを追加します。 これを行う最も簡単な方法は、テストでの呼び出しからクラスとメソッドのスタブを生成することです。

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

テストからクラスとメソッドを生成するには

まず、新しいクラスが既に存在しない限り、新しいクラスを追加するプロジェクトを作成します。

クラスを生成するには

  1. 生成するクラスの例 ( LocalMathなど) にカーソルを置き、[ クイック アクションとリファクタリング] を選択します。
  2. ショートカット メニューの [ 新しい型の生成] を選択します。
  3. [ タイプの生成 ]ダイアログ ボックスで、[ プロジェクト ]をクラス ライブラリ プロジェクトに設定します。 この例では、 Fabrikam.Math です

メソッドを生成するには

  1. SquareRootなどのメソッドの呼び出しにカーソルを置き、[クイック アクションとリファクタリング] を選択します。
  2. ショートカット メニューの [ Generate method 'SquareRoot" を選択します。

最初のテストを実行する

テストをビルドして実行します。 テスト結果は赤い 失敗インジケーター を示し、テストは 失敗したテストの一覧の下に表示されます。

1 つの失敗したテストを示すテスト エクスプローラーのスクリーンショット。

コードを簡単に変更します。

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

テストをもう一度実行すると成功します。

1 つのテストに合格した単体テスト エクスプローラーのスクリーンショット。

単体テストを実行するには

単体テストを実行するには:

  • [テスト>すべてのテストを実行する] を選択する
  • または、 テスト エクスプローラー が開いている場合は、[ 実行 ] または [ すべてのテストをビューで実行] を選択します。

[すべて実行] ボタンを示すテスト エクスプローラーのスクリーンショット。

[失敗したテスト] にテストが表示された場合は、たとえば名前をダブルクリックしてテストを開きます。 テストが失敗したポイントがコード エディターに表示されます。

  • テストの完全な一覧を表示するには、[ すべて表示] を選択します。

  • テスト結果の詳細を表示するには、 テスト エクスプローラーでテストを選択します。

  • テストのコードに移動するには、テスト エクスプローラーでテストをダブルクリックするか、ショートカット メニューの [ テストを開く ] を選択します。

  • テストをデバッグするには、1 つ以上のテストのショートカット メニューを開き、[ デバッグ] を選択します。

  • ソリューションをビルドするたびにバックグラウンドでテストを実行するには、[ 設定] アイコンの横にある矢印を選択し、[ ビルド後にテストを実行] を選択します。 以前に失敗したテストは、最初に実行されます。

インターフェイスに同意する

画面を共有することで、コンポーネントを使用する同僚と共同作業を行うことができます。 同僚は、多くの関数が前のテストに合格するとコメントするかもしれません。 このテストは、関数の名前とパラメーターが正しいことを確認するためだけであり、この関数の主な要件をキャプチャするテストを記述できることを説明します。

同僚と共同作業して、次のテストを記述します。

[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);
}

ヒント

この関数では、 テストの最初の開発を使用します。最初に機能の単体テストを記述してから、テストを満たすコードを記述します。 それ以外の場合、この方法は現実的ではないので、コードを記述した後にテストを記述します。 ただし、コードの前でも後でも、単体テストを記述することは非常に重要です。これは、コードが安定しているためです。

赤、緑、リファクタリング...

テストを繰り返し記述し、失敗したことを確認するサイクルに従い、テストを成功させるコードを記述してから、リファクタリングを検討します。これにより、テストを変更せずにコードが改善されます。

Red

作成した新しいテストを含むすべてのテストを実行します。 テストを記述した後は、必ずテストを実行して失敗したことを確認してから、合格させるコードを記述します。 たとえば、記述した一部のテストにアサーションを配置し忘れた場合、 失敗 の結果が表示されると、合格すると、テスト結果が要件を満たしていることが正しく示されるという確信が得られます。

もう 1 つの便利な方法は、 ビルド後にテストの実行を設定することです。 このオプションでは、ソリューションをビルドするたびにバックグラウンドでテストが実行されるため、コードのテスト状態を継続的にレポートできます。 この方法によって Visual Studio の応答が遅くなる可能性があることを懸念しているかもしれませんが、これはめったに発生しません。

1 つの失敗したテストを含むテスト エクスプローラーのスクリーンショット。

Green

開発しているメソッドのコードで最初の試行を書き込みます。

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;
    }

テストをもう一度実行すると、すべてのテストが成功します。

2 つのテストに合格した単体テスト エクスプローラーのスクリーンショット。

リファクター

コードでメイン関数が実行されたので、コードを見て、パフォーマンスを向上させる方法を見つけるか、将来簡単に変更できるようにします。 ループで実行される計算の数を減らすことができます。

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;
    }

テストが引き続き合格することを確認します。

ヒント

  • コードの開発中に行うすべての変更は、リファクタリングまたは拡張機能である必要があります。

    • リファクタリングとは、新しい機能を追加していないためにテストを変更しないことを意味します。
    • 拡張機能とは、既存のテストと新しいテストの両方に合格するために必要なテストを追加し、コードを変更することを意味します。
  • 既存のコードを変更された要件に更新する場合は、現在の要件を表さなくなった古いテストも削除します。

  • 既に合格したテストを変更しないでください。 代わりに、新しいテストを追加します。 実際の要件を表すテストのみを記述します。

  • 変更のたびにテストを実行します。

...を繰り返します。

小さな手順の一覧を大まかなガイドとして使用して、一連の拡張機能とリファクタリングの手順を続行します。 各拡張機能の後に必ずしもリファクタリング手順を実行するとは限りません。また、複数のリファクタリング手順を連続して実行する場合があります。 ただし、コードを変更するたびに、必ず単体テストを実行します。

場合によっては、コードを変更する必要がないテストを追加しますが、コードが正しく動作すると確信できます。 たとえば、関数が幅広い入力に対して動作することを確認します。 次のようなテストをさらに記述します。

[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);
}

このテストは、初回実行時に合格します。

3 つのテストに合格したテスト エクスプローラーのスクリーンショット。

この結果が間違いではないことを確認するために、テストに一時的に小さなエラーを導入して失敗させることができます。 エラーが表示されたら、もう一度修正できます。

ヒント

テストに合格する前に、必ずテストを失敗してください。

Exceptions

次に、例外的な入力のテストの記述に進みます。

[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 秒以内にコードが終了します。

ビルド サーバーで無限ループが発生しないようにする必要があります。 サーバーは完全な実行でタイムアウトを課しますが、タイムアウトが非常に長く、大幅な遅延が発生します。 そのため、このテストに明示的なタイムアウトを追加できます。

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

明示的なタイムアウトにより、テストが失敗します。

この例外的なケースに対処するようにコードを更新します。

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

Regression

新しいテストは成功しますが、回帰があります。 合格に使用したテストが失敗しました。

以前に成功した単体テストが失敗したスクリーンショット。

間違いを見つけて修正する:

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

修正後、すべてのテストに合格します。

4 つのテストに合格した単体テスト エクスプローラーのスクリーンショット。

ヒント

コードに対して行った変更のたびに、すべてのテストが合格することを確認します。

コード カバレッジ

作業中の間隔で、最後にコードをチェックインする前に、コード カバレッジ レポートを取得します。 これは、テストによって実行されたコードの量を示しています。

あなたのチームは、少なくとも80の%のカバレッジを目指しています. 生成されたコードに対するこの要件は緩和されます。これは、この種類のコードに対して高いカバレッジを実現することが困難な場合があるためです。

適切なカバレッジは、コンポーネントの完全な機能がテストされたことを保証するものではありません。また、すべての入力値に対してコードが動作することを保証するものではありません。 ただし、コード行のカバレッジとコンポーネントの動作空間のカバレッジの間には、かなり密接な相関関係があります。 そのため、適切なカバレッジにより、必要なほとんどの動作をテストするというチームの信頼度が高まります。

コード カバレッジ レポートを取得するには、Visual Studio の [テスト ] メニューの [ すべてのテストのコード カバレッジの分析] を選択します。 すべてのテストが再度実行されます。

コード カバレッジの結果と [色の表示] ボタンのスクリーンショット。

レポートの合計を展開すると、開発中のコードに完全なカバレッジがあることを示します。 重要なスコアはテスト対象のコード用であるため、これは非常に満足です。 明らかにされたセクションは、実際にはテスト自体にあります。

[ コード カバレッジの色分け 表示] ボタンを切り替えることで、テスト コードのどの部分が実行されていないかを確認できます。 テストで使用されなかったコードは、オレンジ色で強調表示されます。 ただし、これらのセクションはテスト コード内にあり、エラーが検出された場合にのみ使用されるため、カバレッジにとって重要ではありません。

特定のテストがコードの特定の分岐に到達することを確認するには、[ コード カバレッジの色分け 表示] を設定し、ショートカット メニューの [実行 ] コマンドを使用して 1 つのテストを実行します。

いつ終わったのですか?

満足できるまで、コードは引き続き小さな手順で更新します。

  • 使用可能なすべての単体テストに合格します。

    単体テストのセットが非常に大きいプロジェクトでは、開発者がそれらすべてが実行されるのを待つのは現実的ではない可能性があります。 代わりに、プロジェクトはゲート チェックイン サービスを運用します。このサービスでは、ソース ツリーにマージされる前に、チェックインされたシェルブセットごとにすべての自動テストが実行されます。 実行が失敗した場合、チェックインは拒否されます。 これにより、開発者は自分のマシンで最小限の単体テストセットを実行し、ビルドを中断するリスクを実行せずに他の作業を続行できます。 詳細については、「 ゲート チェックイン ビルド プロセスを使用して変更を検証する」を参照してください。

  • コード カバレッジはチームの標準を満たしています。 75% が一般的なプロジェクト要件です。

  • 単体テストでは、一般的な入力と例外的な入力の両方を含め、必要な動作のあらゆる側面をシミュレートします。

  • コードを理解し、拡張するのは簡単です。

これらの条件がすべて満たされたら、コードをソース管理にチェックインする準備が整います。

単体テストを使用したコード開発の原則

コードの開発時に、次の原則を適用します。

  • コードと共に単体テストを開発し、開発中に頻繁に実行します。 単体テストは、コンポーネントの仕様を表します。
  • 要件が変更されたか、テストが間違っている場合を除き、単体テストを変更しないでください。 コードの機能を拡張するときに、新しいテストを徐々に追加します。
  • コードの少なくとも 75% がテストでカバーされるようにします。 ソース コードをチェックインする前に、コード カバレッジの結果を間隔を指定して確認します。
  • 単体テストをコードと共にチェックインして、継続的または通常のサーバー ビルドによって実行されるようにします。
  • 実用的な場合は、機能の各部分について、最初に単体テストを記述します。 これを行う前に、それを満たすコードを開発してください。

変更をチェックインする

変更をチェックインする前に、もう一度同僚と画面を共有して、作成した内容を非公式かつ対話的に確認できるようにします。 テストは、コードのしくみではなく、主にコードの機能に関心を持つ同僚とのディスカッションの焦点であり続けます。 これらの同僚は、あなたが書いたことが彼らのニーズを満たしていることを同意する必要があります。

テストとコードの両方を含め、行ったすべての変更をチェックインし、完了したタスクに関連付けます。 チェックインは、チームの自動チーム ビルド システムをキューに入れ、チームの CI ビルド ビルド プロセスを使用して変更を検証します。 このビルド プロセスは、開発用コンピューターとは別のクリーンな環境で、チームが行うすべての変更をビルドしてテストすることで、コードベースのエラーを最小限に抑えるのに役立ちます。

ビルドが完了すると通知されます。 ビルド結果ウィンドウで、ビルドが成功し、すべてのテストが成功したことがわかります。

変更をチェックインするには

  1. チーム エクスプローラーの [マイ ワーク] ページで、[チェックイン] を選択します。

    [マイ ワーク] からのチェックインのスクリーンショット。

  2. [ 保留中の変更] ページで、次の点を確認します。

    • 関連するすべての変更は、[ 含まれる変更] に一覧表示されます。
    • 関連するすべての作業項目は、 関連する作業項目に一覧表示されます。
  3. コメントを入力すると、変更されたファイルとフォルダーのバージョン 管理履歴をチームが確認するときに、これらの変更の目的を理解しやすくなります。

  4. [ チェックイン] を選択します。

    保留中の変更をチェックインするスクリーンショット。

コードを継続的に統合するには

継続的インテグレーション ビルド プロセスを定義する方法の詳細については、「 CI ビルドの設定」を参照してください。 このビルド プロセスを設定したら、チーム ビルドの結果に関する通知を受け取ることができます。

ビルドが成功した [マイ ビルド] ページのスクリーンショット。

詳細については、「ビルドの 実行、監視、管理」を参照してください。

次のステップ