複数のテスト値を1つのテストメソッドでテストする - Theory属性の利用 - C#

xUnitのテストで複数のテスト値を1つのテストメソッドでテストする方法を紹介します。

概要

こちらの記事ではxUnitを利用したテストの実装を紹介しました。
通常、1つのテストを1つのテストメソッドで記述しますが、テストケースの入力の値が異なるだけで同じテストを実施する場合、コードが冗長になってしまいます。 この記事では、複数のテストケースを1つのテストメソッドでテストする記述方法を紹介します。

冗長な例

テストされるプログラムとして、下記のクラスライブラリを作成します。
MyClass.cs
using System;

namespace xUnitTheorySimple
{
  public class MyClass
  {
    public int calc(int a, int b, int c)
    {
      if (a == 2) a = 3; //バグ

      return (a + b) * c;
    }

  }
}



テストプロジェクトを作成し、クラスライブラリの参照を追加します。具体的な手順はこちらの記事を参照して下さい。
テストプログラムのテストクラスに以下のコードを記述します。
UnitTest1.cs
using System;
using Xunit;
using xUnitTheorySimple;

namespace xUnitTheorySimpleTest
{
  public class UnitTest1
  {
    [Fact]
    public void Test1()
    {
      MyClass mc = new MyClass();
      Assert.True( mc.calc(1, 2, 3) == 9, "NG");
    }

  }
}



テストを実行します。テストはOKになります。


テストケースを増やします。コードを追記して以下の状態にします。
UnitTest1.cs
using System;
using Xunit;
using xUnitTheorySimple;

namespace xUnitTheorySimpleTest
{
  public class UnitTest1
  {
    [Fact]
    public void Test1()
    {
      MyClass mc = new MyClass();
      Assert.True( mc.calc(1, 2, 3) == 9, "NG");
    }
    [Fact]
    public void Test2()
    {
      MyClass mc = new MyClass();
      Assert.True(mc.calc(1, 1, 1) == 2, "NG");
    }

    [Fact]
    public void Test3()
    {
      MyClass mc = new MyClass();
      Assert.True(mc.calc(3, 3, 2) == 12, "NG");
    }
  }
}



テストを実行します。3つのテストメソッドが実行されます。


テストはできましたが、値が違うだけで同じ内容のテストメソッドを記述するのは冗長です。 テストの値のみを変えてシンプルに記述したいです。

Theory属性を利用したテストメソッド

Theory属性を利用すると上記のテストメソッドをシンプルに記述できます。

コード

UnitTest1のテストクラスのコードを以下のコードに変更します。
UnitTest1.cs
using System;
using Xunit;
using xUnitTheorySimple;

namespace xUnitTheorySimpleTest
{
  public class UnitTest1
  {
    [Theory]
    [InlineData(1, 2, 3, 9)]
    [InlineData(1, 1, 1, 2)]
    [InlineData(3, 3, 2, 12)]
    public void Test1(int a, int b, int c, int d)
    {
      MyClass mc = new MyClass();
      Assert.True(mc.calc(a, b, c) == d, "NG");
    }
  }
}

解説

Theory属性を記述することで、テストメソッドに値をInlineData から与えられるようになります。
    [Theory]

テストメソッド Test1 に与えるテストケースの値です。最初の3つの値が MyClassのcalc() メソッドに与える値になります。 4つ目の値が、期待される結果の値です。
    [InlineData(1, 2, 3, 9)]
    [InlineData(1, 1, 1, 2)]
    [InlineData(3, 3, 2, 12)]

テストメソッドの実装です。InlineData の値がメソッドの引数に与えられます。
    public void Test1(int a, int b, int c, int d)
    {
      MyClass mc = new MyClass();
      Assert.True(mc.calc(a, b, c) == d, "NG");
    }

実行結果

テストを実行します。下図の結果になります。Test1 メソッドに子要素が表示され、それぞれの値のテスト結果が表示されます。

実行結果2

さらにテストケースを加えてバグを発見できました。
問題のある値に[×]のアイコンが表示されます。

using System;
using Xunit;
using xUnitTheorySimple;

namespace xUnitTheorySimpleTest
{
  public class UnitTest1
  {
    [Theory]
    [InlineData(1, 2, 3, 9)]
    [InlineData(1, 1, 1, 2)]
    [InlineData(3, 3, 2, 12)]
    [InlineData(2, 1, 2, 6)]
    [InlineData(3, 4, 1, 7)]
    public void Test1(int a, int b, int c, int d)
    {
      MyClass mc = new MyClass();
      Assert.True(mc.calc(a, b, c) == d, "NG");
    }
  }
}


Theory属性を利用したテストメソッドを実装できました。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2021-08-23
iPentec all rights reserverd.