メインコンテンツまでスキップ

「C#」タグの記事が1件件あります

全てのタグを見る

初級者向け!ユニットテストを使ってカバレッジを計測、テストの品質を向上させよう

鶴田
開発一部第2課

今回の記事では、ユニットテストを使ってカバレッジを計測し、さらに向上させる方法を解説します。

ユニットテストとは、プログラムの一部分を独立してテストする手法で、主に早期のバグ発見が目的です。 ユニットテストを導入すると、テストが十分に行き届いているかを確認できるようになり、テスト品質の 向上にも大いに役立ちます。さらに、リファクタリングや仕様変更の際に安心してコードを修正できるようになり、 開発効率の向上にも貢献するなど、開発全体において非常に重要な役割を果たします。

カバレッジとは、テスト対象のプログラムのどの部分が実際にテストされているかを示す指標です。 カバレッジを計測することで、テストが漏れている部分が明確になり、より高品質なテストへと つなげられます。

私自身、「ユニットテストでカバレッジを計測して品質を上げる」方法は、経験の浅いプログラマーにも わかりやすく効果的だと考えています。高品質な成果物はチーム全体の意識を高めるだけでなく、 モチベーションの向上にもつながります。 経験が浅い方でも、ユニットテストを活用すればチームに十分貢献できるでしょう。

「何から手を付ければいいかわからない」という方こそ、ぜひ参考にしてみてください。

動作環境

  • 開発環境: Visual Studio 2022 Community
  • 言語: C#

今回作成するプログラムの仕様

  • 製品クラス
    品番ごとに製品の名前と価格、廃番日付を保持する

  • 在庫クラス
    品番ごとに在庫数を保持する

  • 上記2クラスのユニットテストクラス

作成手順

  1. プロジェクトを2つ追加する

    • 1つ目のプロジェクト

      • プロジェクトの種類: クラスライブラリ
      • プロジェクトの名前: ClassLibrary1
    • 2つ目のプロジェクト

      • プロジェクトの種類: MSTestテストプロジェクト
      • プロジェクトの名前: TestProject1

    もともとある Class1.cs は削除してください。

  2. ClassLibrary1 に製品クラスと在庫クラスを追加する

製品マスタは「品番、製品名、価格、廃番日付」のプロパティを、在庫マスタは「品番、在庫数」のプロパティを持つようにします。下記のコードを追加してください。

製品クラス(Product)と在庫クラス(Zaiko)

public class Product
{
/// <summary>
/// 製品CD
/// </summary>
public string ProductCode { get; }

/// <summary>
/// 製品名称
/// </summary>
public string Name { get; }

/// <summary>
/// 価格
/// </summary>
public decimal Price { get; }

/// <summary>
/// 廃番日付
/// </summary>
public string? HaibanDate { get; }

public Product(string productCode, string name, decimal price)
{
if (string.IsNullOrWhiteSpace(productCode)) throw new ArgumentException("製品CDは必須です");
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("名称は必須です");
if (price < 0) throw new ArgumentException("製品価格は必須です");
if (haibanDate != null)
{
if (!DateTime.TryParseExact(haibanDate, "yyyyMMdd", null, System.Globalization.DateTimeStyles.None, out _))
throw new ArgumentException("廃番日付が有効な日付ではない");
}

ProductCode = productCode;
Name = name;
Price = price;
HaibanDate = haibanDate;
}
}

public class Zaiko
{
public string ProductCode { get; }
public int ZaikoSu { get; private set; }

public Zaiko(string productCode, int zaikoSu)
{
if (string.IsNullOrWhiteSpace(productCode)) throw new ArgumentException("製品CDは必須");
if (zaikoSu < 0) throw new ArgumentException("在庫数はゼロ以上のみ有効");

ProductCode = productCode;
ZaikoSu = zaikoSu;
}

public void AddZaikoSu(int amount)
{
if (amount <= 0) throw new ArgumentException("追加在庫数はゼロ以上のみ有効");
ZaikoSu += amount;
}
}

  1. TestProject1 にテストコードを追加する
[TestClass]
public class ProductTests
{
[TestMethod]
[Priority(0001)] // テストの優先度
public void コンストラクタ01()
{
var target = new Product("001", "商品A", 100, "20250101");
Assert.AreEqual("001", target.ProductCode);
Assert.AreEqual("商品A", target.Name);
Assert.AreEqual(100, target.Price);
Assert.AreEqual(target.HaibanDate, "20250101");
}
}
  1. 在庫クラスのテストコードを追加する
[TestClass]
public class ZaikoTests
{
[TestMethod]
[Priority(0001)]
public void コンストラクタ()
{
var target = new Zaiko("001", 10);
Assert.AreEqual("001", target.ProductCode);
Assert.AreEqual(10, target.ZaikoSu);
}
}

Visual Studio でテストを実行すると、テストが実行され、テスト結果が表示されます。

テストエクスプローラー実行結果

これで完成・・・でしょうか?

それを確認するために、カバレッジを計測してみましょう。

VisualStudio 2022 へ Fine Code Coverage を導入する

  1. カバレッジを計測するために、以下のツールを使用します。

coverlet.console NuGet パッケージマネージャーより、coverlet.console をインストールします。

Fine Code Coverage https://marketplace.visualstudio.com/items?itemName=FortuneNgwenya.FineCodeCoverage

拡張機能より、Fine Code Coverage を検索してインストールしてください。

Visual Studio を再起動すると、ツールバーに Fine Code Coverage が表示されます。

拡張機能→Fine Code Coverage→設定 より色の設定を確認してください。以下の設定がおすすめです。

Fine Code Coverageおすすめ

Fine Code Coverage についての詳しい解説は、以下のサイトも参考になります。

カバレッジ100%へ

先ほどまで作成したソリューションを再度開いて、テストを実行します。

在庫クラスを確認してみましょう。

カバレッジ結果

オレンジや赤色の背景色がコード内に表示されています。 これは、赤はテストが実行されていない行(C0カバレッジ未達成)、オレンジは分岐の一部がテストされていない行(C1カバレッジ未達成)を示しています。

この行が「テストの漏れ」です。放置してはいけません。テストコードを追加します。

テストコードを以下の通り追加してください。

[TestClass]
public class ProductTests
{
[TestMethod]
[Priority(0001)] // テストの優先度を設定
public void コンストラクタ()
{
var target = new Product("001", "商品A", 100, "20250101");
Assert.AreEqual("001", target.ProductCode);
Assert.AreEqual("商品A", target.Name);
Assert.AreEqual(100, target.Price);
Assert.AreEqual(target.HaibanDate, "20250101");
}

[TestMethod]
[Priority(0002)]
public void コンストラクタ_Exception_ProductCode()
{
Assert.ThrowsException<ArgumentException>(() => new Product("", "商品A", 100));
}
/*
* 以下の通りにも記述可能です。
* ただ、カバレッジツールの制約上最後の } が未テスト行として認識されます。
*
[Priority(0002)]
[ExpectedException(typeof(ArgumentException))] // 例外が発生することを確認するテストコード
public void コンストラクタ_Exception_ProductCode()
{
var target = new Product("", "商品A", 100);
}
*/

[TestMethod]
[Priority(0003)]
public void コンストラクタ_Exception_Name()
{
Assert.ThrowsException<ArgumentException>(() => new Product("001", "", 100));
}

[TestMethod]
[Priority(0004)]
public void コンストラクタ_Exception_Price()
{
Assert.ThrowsException<ArgumentException>(() => new Product("001", "商品A", -1M));
}

[TestMethod]
[Priority(0005)]
public void コンストラクタ_Exception_HaibanDate()
{
Assert.ThrowsException<ArgumentException>(() => new Product("001", "商品A", 100, "100"));
}
}

public class ZaikoTests
{
[TestMethod]
[Priority(0001)]
public void コンストラクタ()
{
var target = new Zaiko("001", 10);
Assert.AreEqual("001", target.ProductCode);
Assert.AreEqual(10, target.ZaikoSu);
}

[TestMethod]
[Priority(0002)]
public void コンストラクタ_Exception_ProductCode()
{
Assert.ThrowsException<ArgumentException>(() => new Zaiko("", 10));
}

[TestMethod]
[Priority(0003)]
public void コンストラクタ_Exception_ZaikoSu()
{
Assert.ThrowsException<ArgumentException>(() => new Zaiko("001", -1));
}

[TestMethod]
[Priority(0101)]
public void AddZaikoSu_Exception()
{
var target = new Zaiko("001", 10);
Assert.ThrowsException<ArgumentException>(() => target.AddZaikoSu(-1));
}

[TestMethod]
[Priority(0102)]
public void AddZaikoSu()
{
var target = new Zaiko("001", 10);
target.AddZaikoSu(1);
Assert.AreEqual(11, target.ZaikoSu);
}
}

これですべての行がテストされました。 Fine Code Coverage で確認してみましょう。

表示→その他のウィンドウ→Fine Code Coverage を選択します。

カバレッジ結果

確かにカバレッジの欄には燦然と輝く100%の文字がっ!

これで、テストの漏れがなくなりました。

もちろん、カバレッジを100%にしたからといって、バグが完全になくなるわけではありません。しかし、ユニットテストを書く過程でコードを深く理解できるようになり、結果として品質向上につながります。

ぜひ、ユニットテストを書いてカバレッジを活用してみてください。そうすることで、チーム全体の品質意識が高まり、開発効率も向上するはずです。