Assert チートシート

  • C#
  • xUnit

Assertクラスの検証メソッドのチートシートです。
自分用にまとめていましたが、ボリュームが割と大きくなったので公開しないのは少しもったいないと思ったのと、
バージョンアップで追加されている新しいメソッドの日本語の情報が少ないと感じたため、公開することにしました。

どなたかのお役に立てれば。

環境

  • Visual Studio Community 2022 (64 ビット) - Version 17.3.3
  • Microsoft.NET.Test.Sdk - 17.3.1
  • xUnit - 2.4.2

メソッド一覧

値が等しいか(Assert.Equal)

// Assert.Equal(期待値, 実行値)
Assert.Equal("1", 1.ToString());

// シーケンスも比較可。
Assert.Equal(new[] { "1", "2", }, "1,2".Split(',')); // T[]
Assert.Equal(new List<string>() { "1", "2", }, "1,2".Split(',')); // IEnumerable<string>

値が厳密に等しいか(Assert.StrictEqual)

// Assert.StrictEqual(期待値, 実行値)
Assert.StrictEqual("1", 1.ToString());

// EqualityComparer<T>.Defaultが比較に使用されるため、
// Assert.Equalで比較可能だったシーケンスの要素比較は不可。
// 配列の場合は以下のように同一インスタンスであればパスする。
var texts = new string[] { "1", "2", };
Assert.StrictEqual(texts, texts);

値が等しくないか(Assert.NotEqual)

// Assert.NotEqual(期待値, 実行値);
Assert.NotEqual("1", 1.ToString());

// シーケンスも比較可。
Assert.NotEqual(new[] { "1", "2", }, "1,2,3".Split(',')); // T[]
Assert.NotEqual(new List<string>() { "1", "2", }, "1,2,3".Split(',')); // IEnumerable<string>

値が厳密に等しくないか(Assert.NotStrictEqual)

// Assert.NotStrictEqual(期待値, 実行値);
Assert.NotStrictEqual("1", 2.ToString());

// EqualityComparer<T>.Defaultが比較に使用されるため、
// Assert.NotEqualで比較可能だったシーケンスの要素比較は不可。
// 配列の場合は以下のように要素値が同じでもインスタンスが違えばパスする。
Assert.NotStrictEqual(new[] { "1", "2", }, "1,2".Split(','));

同一インスタンスか(Assert.Same)

// Assert.Same(期待値, 実行値)
var s1 = "abc";
var s2 = s1;
Assert.Same(s2, s1);

同一インスタンスでないか(Assert.NotSame)

// Assert.NotSame(期待値, 実行値)
var s1 = "abc";
var s2 = new string("abc");
Assert.NotSame(s2, s1);

オブジェクトが同等か(Assert.Equivalent)

// Assert.Equivalent(期待値, 実行値)

// nullの場合、nullとのみ同等。strictの影響は受けない。
Assert.Equivalent(null, null);
Assert.Equivalent(null, null, strict: true);

// 値型及び文字列の場合、等価(Equal)と同等(Equivalent)は同じ。strictの影響は受けない。
Assert.Equivalent("a", "a");
Assert.Equivalent("a", "a", strict: true);
Assert.Equivalent(true, true);
Assert.Equivalent(true, true, strict: true);
Assert.Equivalent(1f, 1f);
Assert.Equivalent(1f, 1f, strict: true);
// 型は厳密に同じでないとNG。
Assert.Equivalent(1, 1);
// ↓これは値は同じだがintとlongの比較なのでテスト失敗する
// Assert.Equivalent(1, 1L);

// KeyValuePair<,>は値型だが特別扱いされており、
// 単純なEquals()での比較ではなく、値(Value)とキー(Key)の両方に対して比較が行われる。
// これにより、キーや値にコレクションを格納して比較することが可能。
var kvp1 = new KeyValuePair<int[], int>(new[] { 1, 2, 3, }, 1);
var kvp2 = new KeyValuePair<int[], int>(new[] { 3, 2, 1, }, 1);
var dic1 = new Dictionary<int[], int>()
{
    { new[] { 1, 2, 3, }, 1 },
    { new[] { 4, 5, 6, }, 2 },
};
var dic2 = new Dictionary<int[], int>()
{
    { new[] { 3, 2, 1, }, 1 },
    { new[] { 6, 5, 4, }, 2 },
};
Assert.Equivalent(kvp1, kvp2);
Assert.Equivalent(dic1, dic2);

// コレクションは、順序や型に関係なく同じ要素があるかどうか比較される。
Assert.Equivalent(new[] { 1, 2, }, new List<int>() { 2, 1, });
Assert.Equivalent(new[] { 1, 2, }, new[] { 2, 3, 1, }, strict: false);
// strict=trueの場合は、実行値が期待値と同じ数・同じ要素になる必要がある。
Assert.Equivalent(new[] { 1, 2, 3, }, new[] { 2, 3, 1, }, strict: true);
// ↓これはテスト失敗する
//Assert.Equivalent(new[] { 1, 2, }, new[] { 2, 3, 1, }, strict: true);

// 同じインスタンスを指す参照型の場合、常に同等。strictの影響は受けない。
var bar1 = new Bar();
Assert.Equivalent(bar1, bar1);

// ↓循環参照はテスト失敗。
//var bar2 = new Bar();
//bar1.BarValue = bar2;
//bar2.BarValue = bar1;
//Assert.Equivalent(bar1, bar2);

// その他の参照型との比較は、フィールド名またはプロパティ名とその値が同等であるかが比較される。
// フィールドかプロパティかは関係なく、メンバー名と値が同等であればテスト成功。
var f = new FieldValues<int, string>(1, "A");
var p = new PropertyValues<int, string>(1, "A");
Assert.Equivalent(f, p);
Assert.Equivalent(f, new { Value1 = 1, Value2 = "A", });
// ↓値は同じだがメンバー名が違うのでNG
//Assert.Equivalent(f, new { Field1 = 1, Field2 = "A", });
// ↓メンバー名は同じだが値が違うのでNG
//Assert.Equivalent(f, new { Value1 = 2, Value2 = "B", });

// strict=falseなら実行値のメンバー数が同等以上(期待値の上位集合)かつ値が同じならテスト成功。
// strict=trueなら実行値のメンバー数が同じ(期待値と完全一致)かつ値が同じならテスト成功。
var a1 = new { Value1 = 1, Value2 = "A", };
var a2 = new { Value1 = 1, Value2 = "A", Value3 = DateTime.Now, };
var a3 = new { Value1 = 1, };
var a4 = new { Value1 = 1, Value2 = "A", };
// ↓strict=false: a2(実行値)はa1(期待値)の上位集合なので成功。
Assert.Equivalent(a1, a2, strict: false);
// ↓strict=false: a3(実行値)はa1(期待値)の部分集合なので失敗。
//Assert.Equivalent(a1, a3, strict: false);
// ↓strict=true: a3(実行値)はa1(期待値)の部分集合なので(=完全一致ではないので)失敗。
//Assert.Equivalent(a1, a3, strict: true);
// ↓strict=true: a4(実行値)はa1(期待値)と完全一致なので成功。
Assert.Equivalent(a1, a4, strict: true);

// 検証用クラス
public class Bar
{
    public Bar? BarValue { get; set; }
}
public class FieldValues<T1, T2>
{
    public readonly T1 Value1;
    private readonly T2 Value2;
    public FieldValues(T1 value1, T2 value2) => (Value1, Value2) = (value1, value2); 
}
public class PropertyValues<T1, T2>
{
    public T1 Value1 { get; }
    private T2 Value2 { get; }
    public PropertyValues(T1 value1, T2 value2) => (Value1, Value2) = (value1, value2);
}

文字列が正規表現と一致するか(Assert.Matches)

// Assert.Matches(正規表現, テスト文字列)
Assert.Matches("^abc", "abc123");
Assert.Matches(new System.Text.RegularExpressions.Regex("123$"), "abc123");

文字列が正規表現と一致しないか(Assert.DoesNotMatch)

// Assert.DoesNotMatch(正規表現, テスト文字列)
Assert.DoesNotMatch("^123", "abc123");
Assert.DoesNotMatch(new System.Text.RegularExpressions.Regex("abc$"), "abc123");

値が含まれるか(Assert.Contains)

// Assert.Contains(値, ソースオブジェクト)

// コレクション
Assert.Contains(1, new[] { 1, 2, 3, 4, 5, });

// 文字列
Assert.Contains("abc", "123abc456");

// 辞書
IDictionary<string, int> dic = new Dictionary<string, int>()
{
    { "key1", 1 },
    { "key2", 2 },
};
Assert.Contains("key1", dic);

値が含まれないか(Assert.DoesNotContain)

// Assert.DoesNotContain(値, ソースオブジェクト)

// コレクション
Assert.DoesNotContain(0, new[] { 1, 2, 3, 4, 5, });

// 文字列
Assert.DoesNotContain("efg", "123abc456");

// 辞書
IDictionary<string, int> dic = new Dictionary<string, int>()
{
    { "key1", 1 },
    { "key2", 2 },
};
Assert.DoesNotContain("key3", dic);

値が範囲に含まれるか(Assert.InRange)

// Assert.InRange(値, 最小値(包括的), 最大値(包括的));
Assert.InRange(5, 0, 10);
Assert.InRange(0, 0, 10);
Assert.InRange(10, 0, 10);

値が範囲に含まれないか(Assert.NotInRange)

// Assert.NotInRange(値, 最小値(包括的), 最大値(包括的));
Assert.NotInRange(-1, 0, 10);
Assert.NotInRange(11, 0, 10);

指定の文字列で始まるか(Assert.StartsWith)

// Assert.StartsWith(開始文字列, 対象文字列)
Assert.StartsWith("abc", "abc123edf");

指定の文字列で終わるか(Assert.EndsWith)

// Assert.EndsWith(終了文字列, 対象文字列)
Assert.EndsWith("edf", "abc123edf");

シーケンスが空であるか(Assert.Empty)

// Assert.Empty(シーケンス)
Assert.Empty(Array.Empty<int>());

シーケンスが空でないか(Assert.NotEmpty)

// Assert.NotEmpty(シーケンス)
Assert.NotEmpty(new[] { 1, 2, });

nullであるか(Assert.Null)

// Assert.Null(オブジェクト)
string? s = null;
Assert.Null(s);

nullでないか(Assert.NotNull)

// Assert.NotNull(オブジェクト)
string s = "abc";
Assert.NotNull(s);

trueであるか(Assert.True)

// Assert.True(bool)
Assert.True(1 == 1);

// Assert.True(bool, 第一引数がtrueでない場合に表示するメッセージ)
Assert.True(1 != 1, "テスト失敗");

falseであるか(Assert.False)

// Assert.False(bool)
Assert.False(1 != 1);

// Assert.False(bool, 第一引数がfalseでない場合に表示するメッセージ)
Assert.False(1 == 1, "テスト失敗");

指定の型であるか(Assert.IsType)

object s = "abc";

// ジェネリック版
// Assert.IsType<型>(オブジェクト)
Assert.IsType<string>(s);

// 非ジェネリック版
// Assert.IsType(型オブジェクト, オブジェクト)
Assert.IsType(typeof(string), s);

指定の型ではないか(Assert.IsNotType)

object s = "abc";

// ジェネリック版
// Assert.IsNotType<型>(オブジェクト)
Assert.IsNotType<int>(s);

// 非ジェネリック版
// Assert.IsNotType(型オブジェクト, オブジェクト)
Assert.IsNotType(typeof(int), s);

指定の型に代入可能であるか(Assert.IsAssignableFrom)

using var ms = new MemoryStream();

// ジェネリック版
// Assert.IsAssignableFrom<型>(オブジェクト)
Assert.IsAssignableFrom<Stream>(ms);

// 非ジェネリック版
// Assert.IsAssignableFrom(型オブジェクト, オブジェクト)
Assert.IsAssignableFrom(typeof(Stream), ms);

指定の例外が発生するか(Assert.Throws, Assert.ThrowsAsync)

var zero = 0;

// ジェネリック版
// Assert.Throws<型>(テストコード)
Assert.Throws<ArgumentException>(new Action(() => throw new ArgumentException()));
Assert.Throws<DivideByZeroException>(() => 1 / zero);

// ArgumentExceptionまたはその派生例外のみで使用可能
// 指定のparamNameと発生例外のparamNameが一致していればテストがパスされる。
// Assert.Throws<ArgumentExceptionまたはその派生型>(指定paramName, テストコード)
Assert.Throws<ArgumentException>("abc", new Action(() => throw new ArgumentException("msg", "abc")));

// 非ジェネリック版
// Assert.Throws(型オブジェクト, テストコード)
Assert.Throws(typeof(ArgumentException), new Action(() => throw new ArgumentException()));
Assert.Throws(typeof(DivideByZeroException), () => 1 / zero);


// 非同期ジェネリック版
// Assert.ThrowsAsync<型>(テストコード)
await Assert.ThrowsAsync<DivideByZeroException>(() => Task.Run(() => 1 / zero));

// ArgumentExceptionまたはその派生例外のみで使用可能
// 指定のparamNameと発生例外のparamNameが一致していればテストがパスされる。
// Assert.ThrowsAsync<ArgumentExceptionまたはその派生型>(指定paramName, テストコード)
await Assert.ThrowsAsync<ArgumentException>("abc", () => Task.Run(new Action(() => throw new ArgumentException("msg", "abc"))));

// 非同期非ジェネリック版
// Assert.ThrowsAsync(型オブジェクト, テストコード)
await Assert.ThrowsAsync(typeof(DivideByZeroException), () => Task.Run(() => 1 / zero));

指定の例外またはその派生例外が発生するか(Assert.ThrowsAny, Assert.ThrowsAnyAsync)

var zero = 0;

// ジェネリック版
// Assert.ThrowsAny<型>(テストコード)
Assert.ThrowsAny<Exception>(new Action(() => throw new ArgumentException()));
Assert.ThrowsAny<Exception>(() => 1 / zero);

// 非ジェネリック版
// 無し。


// 非同期ジェネリック版
// Assert.ThrowsAnyAsync<型>(テストコード)
await Assert.ThrowsAnyAsync<Exception>(() => Task.Run(() => 1 / zero));

// 非同期非ジェネリック版
// 無し。

コレクションの全ての要素がテストをパスするか(Assert.All)

// Assert.All(コレクション, テストコード)
Assert.All(new[] { 0, 2, 4, 6, 8 }, i => Assert.Equal(0, i % 2));

コレクションの要素が単一か(Assert.Single)

// 指定したコレクションの要素が単一か
// Assert.Single(コレクション)
Assert.Single(new[] { 10 });

// 条件に一致する要素が単一か
// Assert.Single(コレクション, 条件)
Assert.Single(new[] { 10, 11, 11, 12 }, i => i == 10);

// 指定した値の要素が単一か
// ※指定した値はボックス化されるので値型はデリゲート使用のものを使ったほうが良い。
// Assert.Single(コレクション, 条件)
Assert.Single(new[] { 10 }, 10);

コレクションに重複する要素が含まれないか(Assert.Distinct)

// Assert.Distinct(コレクション)
Assert.Distinct(new[] { 1, 2, 3, 4, 5, });

コレクションに指定要素数が含まれているかつ全ての要素がテストをパスするか(Assert.Collection)

var values = new[] { 1, 2, 3, 4, 5, };
var texts = "1,2,3,4,5".Split(',');

// コレクションに対するテストコードの配列。
// この配列の要素数が指定要素数代わりとなり、
// コレクションとテストコードの要素数が一致していない場合はテスト失敗となる。
var inspectors = texts.Select(s => new Action<int>(i =>
{
    // 要素が1つでもテスト失敗したらテスト失敗。Assert.Allに似ている。
    Assert.Equal(s, i.ToString());
})).ToArray();

// Assert.Collection(コレクション, テストコード)
Assert.Collection(values, inspectors);

指定した集合がある集合の部分集合であるか(Assert.Subset)

// 部分集合なので、完全一致でもOK。
var target = new HashSet<int>()
{
    1, 2, 3, 4, 5, 6, 7,
};
var hashSet1 = new HashSet<int>()
{
    1, 3, 5, 7,
};
var hashSet2 = new HashSet<int>()
{
    1, 2, 3, 4, 5, 6, 7,
};

// Assert.Subset(対象集合, 部分集合)
Assert.Subset(target, hashSet1);
Assert.Subset(target, hashSet2);

指定した集合がある集合の真部分集合であるか(Assert.ProperSubset)

// 真部分集合なので、完全一致はNG。
var target = new HashSet<int>()
{
    1, 2, 3, 4, 5, 6, 7,
};
var hashSet1 = new HashSet<int>()
{
    1, 3, 5, 7,
};
var hashSet2 = new HashSet<int>()
{
    6, 5, 4, 3, 2, 1,
};
   
// Assert.ProperSubset(対象集合, 真部分集合)
Assert.ProperSubset(target, hashSet1);
Assert.ProperSubset(target, hashSet2);

指定した集合がある集合の上位集合であるか(Assert.Superset)

// 上位集合なので、完全一致でもOK。
var target = new HashSet<int>()
{
    1, 2, 3, 4, 5, 6, 7,
};
var hashSet1 = new HashSet<int>()
{
    0, 1, 2, 3, 4, 5, 6, 7,
};
var hashSet2 = new HashSet<int>()
{
    1, 2, 3, 4, 5, 6, 7
};

// Assert.Superset(対象集合, 上位集合)
Assert.Superset(target, hashSet1);
Assert.Superset(target, hashSet2);

指定した集合がある集合の真上位集合であるか(Assert.ProperSuperset)

// 真上位集合なので、完全一致はNG。
var target = new HashSet<int>()
{
    1, 2, 3, 4, 5, 6, 7,
};
var hashSet1 = new HashSet<int>()
{
    0, 1, 2, 3, 4, 5, 6, 7,
};
var hashSet2 = new HashSet<int>()
{
    1, 2, 3, 4, 5, 6, 7, 8,
};

// Assert.ProperSuperset(対象集合, 真上位集合)
Assert.ProperSuperset(target, hashSet1);
Assert.ProperSuperset(target, hashSet2);

プロパティが変更されるか(Assert.PropertyChanged, Assert.PropertyChangedAsync)

var obj = new System.Dynamic.ExpandoObject();

// 同期版
// Assert.PropertyChanged(
//      INotifyPropertyChangedを実装したオブジェクト, 
//      テストするプロパティ名, 
//      プロパティ変更テストコード
// )
Assert.PropertyChanged(obj, "Text", new Action(() =>
{
    var dic = obj as IDictionary<string, object>;
    dic["Text"] = "abc";
}));

// 非同期版
// Assert.PropertyChangedAsync(
//      INotifyPropertyChangedを実装したオブジェクト, 
//      テストするプロパティ名, 
//      プロパティ変更テストコード
// )
await Assert.PropertyChangedAsync(obj, "Text", () => Task.Run(new Action(() =>
{
    var dic = obj as IDictionary<string, object>;
    dic["Text"] = "abc";
})));

指定のイベント引数を持つイベントが発生するか(Assert.Raises, Assert.RaisesAsync)

// このメソッドでテスト出来るのは、
// イベントハンドラーが EventHandler<T> のイベントのみ。

// 検証用クラス
public class Foo
{
    public event EventHandler<EventArgs>? Bar;
    public void RaiseBar(EventArgs args) => Bar?.Invoke(this, args);
}

var foo = new Foo();

// 同期版
// Assert.Raises<EventArgsの型>(
//      イベントハンドラーのアタッチ,
//      イベントハンドラーのデタッチ,
//      テストコード
// )
Assert.Raises<EventArgs>(
    h => foo.Bar += h,
    h => foo.Bar -= h,
    () =>
    {
        foo.RaiseBar(EventArgs.Empty);
    });

// 非同期版
// Assert.RaisesAsync<EventArgsの型>(
//      イベントハンドラーのアタッチ,
//      イベントハンドラーのデタッチ,
//      テストコード
// )
await Assert.RaisesAsync<EventArgs>(
    h => foo.Bar += h,
    h => foo.Bar -= h,
    () => Task.Run(() =>
    {
        foo.RaiseBar(EventArgs.Empty);
    }));

指定のイベント引数またはその派生のイベント引数を持つイベントが発生するか(Assert.RaisesAny, Assert.RaisesAnyAsync)

// このメソッドでテスト出来るのは、
// イベントハンドラーが EventHandler<T> のイベントのみ。
// Assert.Raises(or RaisesAsync)と違い、イベント引数が派生クラスでもOK。

// 検証用クラス
public class Foo
{
    public event EventHandler<EventArgs>? Bar;
    public void RaiseBar(EventArgs args) => Bar?.Invoke(this, args);
}

var foo = new Foo();

// 同期版
// Assert.RaisesAny<EventArgsの型>(
//      イベントハンドラーのアタッチ,
//      イベントハンドラーのデタッチ,
//      テストコード
// )
Assert.RaisesAny<EventArgs>(
    h => foo.Bar += h,
    h => foo.Bar -= h,
    () =>
    {
        foo.RaiseBar(new CancelEventArgs());
    });

// 非同期版
// Assert.RaisesAnyAsync<EventArgsの型>(
//      イベントハンドラーのアタッチ,
//      イベントハンドラーのデタッチ,
//      テストコード
// )
await Assert.RaisesAnyAsync<EventArgs>(
    h => foo.Bar += h,
    h => foo.Bar -= h,
    () => Task.Run(() =>
    {
        foo.RaiseBar(new CancelEventArgs());
    }));

複数のテストがパスするか(Assert.Multiple)

// Assert.Multiple(テストコード)
Assert.Multiple(
    new Action(() => Assert.True(1 == 1)),
    new Action(() => Assert.Equal(1, 1))
);

テストを失敗させる(Assert.Fail)

// Assert.Fail(メッセージ)
Assert.Fail("テスト失敗");