ひでぼ~blog

C#ときどきゲーム

xUnit.netのTheoryDataを試す

xUnit.netのTheoryDataを使ってテストコードを書いてみます。

実行環境

このような名前と年齢を結合した文字列を返すメソッドのテストコードを書いてみます。

public string GetFullNameWithAge(string lastName, string firstName, int age)
    => $"{lastName} {firstName} ({age})";

TheoryDataを使わない場合

InlineData属性を使ってテストメソッドを書くとこんな感じです。

[Theory]
[InlineData("乙骨", "憂太", 17, "乙骨 憂太 (17)")]
[InlineData("禪院", "真希", 16, "禪院 真希 (16)")]
public void GetFullNameWithAgeTest(string lastName, string firstName, int age, string expected)
{
    var result = GetFullNameWithAge(lastName, firstName, age);

    Assert.Equal(expected, result);
}

また、MemberData属性を使った場合はテストデータ用のメソッドを追加してこのようになります。

public static IEnumerable<object[]> TestData()
{
    yield return new object[] { "乙骨", "憂太", 17, "乙骨 憂太 (17)" };
    yield return new object[] { "禪院", "真希", 16, "禪院 真希 (16)" };
}

[Theory]
[MemberData(nameof(TestData))]
public void GetFullNameWithAgeTest(string lastName, string firstName, int age, string expected)
{
    var result = GetFullNameWithAge(lastName, firstName, age);
    Assert.Equal(expected, result);
}

MemberDataを使う場合、InlineDataではできない少し複雑な引数を入力値として渡すことができるようになります。 例えばInlineDataの引数にはnew DataTime()のようなオブジェクトを渡せませんが、MemberDataではそれが可能です。 MemberDataを使えばすべてOKという感じでしたが、型がobject[]のため、テストメソッドの引数の型と一致しなかった場合に実行時エラーになります。

TheoryDataを使った場合

そこで型を指定できるようになったものがTheoryDataになります。 TheoryData<T1, T2, ...>という型を返すテストデータを定義してMemberData属性に渡します。

public static TheoryData<string, string, int, string> TestTheoryData() => new()
{
    { "乙骨", "憂太", 17, "乙骨 憂太 (17)" },
    { "禪院", "真希", 16, "禪院 真希 (16)" },
};

[Theory]
[MemberData(nameof(TestTheoryData))]
public void GetFullNameWithAgeTest(string lastName, string firstName, int age, string expected)
{
    var result = GetFullNameWithAge(lastName, firstName, age);
    Assert.Equal(expected, result);
}

TheoryDataを使うとobject[]として渡していたものがちゃんと型を明示するようになっているため、コンパイル時にエラーに気づくことができます。

参考

www.thomasbogholm.net