[.NET][C#]NUnitのCollectionAssertアサーションメソッド一覧

# はじめに
[前回](https://qiita.com/suganury/items/e6d9e87ba7f23bfb15a7)、NUnitのStringAssertクラスのアサーションメソッドを一通り試したので
今回はCollectionAssertクラスのアサーションメソッドを一通り試してみる。

# 実施環境
.NET：3.1.401
C#：8.0
NUnit：3.12.0

# CollectionAssertクラス
NUnitのClassicModelのアサーションクラスの1つ。
クラス名の通り、コレクション（IEnumerable実装クラス）を検査する。

## 1. AllItemsAreInstancesOfType
コレクションが保持する要素の型が全て同じかどうかを検査する。
第1引数のコレクションが保持する要素が、第2引数に指定した型か、指定した型のサブクラスのみであればテストOKと判定される。

C#のコレクションは、保持する型をジェネリクスで指定する`ICollection<T>`の実装クラスを使用するのが一般的なので
このアサーションを使用する機会はあまり無いだろう。

```C#
public class Target {}
public class TargetSub : Target {}

public class CollectionAssertTest
{

    [TestCase]
    public void AllItemsAreInstancesOfTypeTest()
    {
        // Test OK.
        CollectionAssert.AllItemsAreInstancesOfType(
            new ArrayList() {"hoge", "fuga", "hage"}, Type.GetType("System.String"));

        // Test NG.
        CollectionAssert.AllItemsAreInstancesOfType(
            new ArrayList() {"hoge", "fuga", new Target()}, Type.GetType("System.String"));

        // Test OK.
        CollectionAssert.AllItemsAreInstancesOfType(
            new ArrayList() {new Target(), new Target(), new TargetSub()}, Type.GetType("AssetionsTest.Target"));
    }
}
  
```

## 2. AllItemsAreNotNull
コレクションが保持する要素の中にnullが含まれるかどうかを検査する。
コレクションが空の場合はテストOKとなる。

```C#

[TestCase]
public void AllItemsAreNotNullTest()
{
    // Test OK.
    CollectionAssert.AllItemsAreNotNull(
        new List<string>() {"hoge", "fuga", "hage"});

    // Test NG.
    CollectionAssert.AllItemsAreNotNull(
        new List<string>() {"hoge", null, "hage"});
        
    // Test OK.
    CollectionAssert.AllItemsAreNotNull(
        new List<string>() {});
}
```

## 3. AllItemsAreUnique
コレクションが保持する要素が全てユニークなものかを検査する。
ユニーク性の判定は`Equalsメソッド`で判定しているようで、
下記コードの1番下の例のように、参照が異なっていても値として同じものが含まれていればテストNGとなる。

```C#

[TestCase]
public void AllItemsAreUniqueTest()
{
    // Test OK.
    CollectionAssert.AllItemsAreUnique(
        new List<string>() {"hoge", "fuga", "hage"});

    // Test NG.
    CollectionAssert.AllItemsAreUnique(
        new List<string>() {"hoge", "hoge", "hage"});

    // Test OK.
    CollectionAssert.AllItemsAreUnique(
        new List<string>() {"hoge", null, "hage"});

    // Test NG.
    CollectionAssert.AllItemsAreUnique(
        new List<string>() {new String("hoge"), new String("hoge"), new String("hage")});

}
```

## 4. AreEqual、AreNotEqual
AreEqualメソッドは、2つのコレクションが保持する要素が格納順序込みで同じものがどうかを検査する。
AreNotEqualメソッドは、その逆の判定を行う。

下記コードの3つ目の例のように、保持する要素が同じでも、格納する順序が異なる場合、テストNGとなる。
順序を無視した検査をしたい場合は、`AreEquivalentメソッド`を使う。

```C#

[TestCase]
public void AreEqualTest()
{
    // Test OK.
    CollectionAssert.AreEqual(
        new List<string>() {"hoge", "fuga", "hage"},
        new List<string>() {"hoge", "fuga", "hage"});

    // Test NG.
    CollectionAssert.AreEqual(
        new List<string>() {"hoge", "fuga", "hage"},
        new List<string>() {"hoge", "hoge", "hage"});

    // Test NG.
    CollectionAssert.AreEqual(
        new List<string>() {"hoge", "fuga", "hage"},
        new List<string>() {"fuga", "hoge", "hage"});

    // Test OK.
    CollectionAssert.AreEqual(
        new List<string>() {"hoge", "fuga", "hage"},
        new List<string>() {new String("hoge"), new String("fuga"), new String("hage")});

}
```

## 5. AreEquivalent、AreNotEquivalent
AreEquivalentメソッドは、2つのコレクションが保持する要素が同じものがどうかを検査する。
AreNotEquivalentメソッドは、その逆の判定を行う。

AreEqualメソッドとは違い、格納順は異なっていてもテストOKとなる。

```C#

[TestCase]
public void AreEquivalentTest()
{
    // Test OK.
    CollectionAssert.AreEquivalent(
        new List<string>() {"hoge", "fuga", "hage"},
        new List<string>() {"hoge", "fuga", "hage"});

    // Test NG.
    CollectionAssert.AreEquivalent(
        new List<string>() {"hoge", "fuga", "hage"},
        new List<string>() {"hoge", "hoge", "hage"});

    // Test OK.
    CollectionAssert.AreEquivalent(
        new List<string>() {"hoge", "fuga", "hage"},
        new List<string>() {"fuga", "hoge", "hage"});

    // Test OK.
    CollectionAssert.AreEquivalent(
        new List<string>() {"hoge", "fuga", "hage"},
        new List<string>() {new String("hoge"), new String("fuga"), new String("hage")});

}
```

## 6. Contains、DoesNotContain
Containsメソッドは、コレクションに指定した要素が含まれるかどうかを検査する。
DoesNotContainメソッドは、その逆の判定を行う。

```C#

[TestCase]
public void ContainsTest()
{
    // Test OK.
    CollectionAssert.Contains(
        new List<string>() {"hoge", "fuga", "hage"},
        "hoge");

    // Test NG.
    CollectionAssert.Contains(
        new List<string>() {"hoge", "fuga", "hage"},
        "HOGE");

    // Test OK.
    CollectionAssert.Contains(
        new List<string>() {"hoge", "fuga", "hage"},
        new String("hoge"));

}
```

## 7. IsSubsetOf、IsNotSubsetOf
IsSubsetOfメソッドは、コレクションが部分的に一致するかどうかを検査する。
IsNotSubsetOfメソッドは、その逆の判定を行う。

第1引数に部分一致させるコレクションを指定、
第2引数に全体となるコレクションを指定する。

```C#
[TestCase]
public void IsSubsetOfTest()
{
    // Test OK.
    CollectionAssert.IsSubsetOf(
        new List<string>() {"hoge", "fuga"},
        new List<string>() {"hoge", "fuga", "hage"});

    // Test NG.
    CollectionAssert.IsSubsetOf(
        new List<string>() {"HOGE", "FUGA"},
        new List<string>() {"hoge", "fuga", "hage"});

    // Test NG.
    CollectionAssert.IsSubsetOf(
        new List<string>() {"hoge", "fuga", "hage"},
        new List<string>() {"hoge", "fuga"});

}
```


## 8. IsEmpty、IsNotEmpty
IsEmptyメソッドは、コレクションが空であることを検査する。
IsNotEmptyメソッドは、その逆の判定を行う。

nullが入っていてもコレクション自体は空ではないのでテスト結果NGとなる。

```C#
[TestCase]
public void IsEmptyTest()
{
    // Test OK.
    CollectionAssert.IsEmpty(
        new List<string>() {});

    // Test NG.
    CollectionAssert.IsEmpty(
        new List<string>() {"hoge"});

    // Test NG.
    CollectionAssert.IsEmpty(
        new List<string>() {null});
}
```


## 9. IsOrdered
コレクションの順序を検査する。
引数にコレクションオブジェクトのみ指定した場合、自然順で要素が格納されていることを検査する。
検査する順序を指定したい場合は、下記コードの一番下の例のように、第2引数に`IComparerインターフェース`を実装したクラスのインスタンスを渡す。

```C#

[TestCase]
public void IsOrderedTest()
{
    // Test OK.
    CollectionAssert.IsOrdered(
        new List<string>() {"A", "B", "C"});

    // Test NG.
    CollectionAssert.IsOrdered(
        new List<string>() {"C", "B", "A"});

    // Test OK.
    CollectionAssert.IsOrdered(
        new List<string>() {null, "A", "B"});

    // Test NG.
    CollectionAssert.IsOrdered(
        new List<string>() {"A", "B", null});

    // Test ArgumentException.
    CollectionAssert.IsOrdered(
        new ArrayList() {"A", "B", new Target()});

    // Test OK.
    CollectionAssert.IsOrdered(
        new List<string>() {"C", "B", "A"},
        new StringOrderDesc()
    );
}

public class StringOrderDesc : Comparer<string>
{
    public override int Compare(string x, string y) => y.CompareTo(x);
}
```

nullは自然順序的には最も小さい値という扱いらしい。

また、型が混在している場合、`ArgumentException`が発生する。
（ジェネリクスを使用していれば発生しないだろうが）

ちなみに`IComparer<T>インターフェース`は`IComparerインターフェース`を継承していないので（なぜだろうか・・・）
`IComparer<T>インターフェース`を実装したクラスを第2引数に渡すことができない。
`Comparer<string>クラス`はその両方をimplementsしているので、ジェネリクスを使用して無用なキャストを避けたい場合は、Comparer<string>クラスのサブクラスを用意する。


# 参考
[NUnit公式：CollectionAssert](https://docs.nunit.org/articles/nunit/writing-tests/assertions/classic-assertions/Collection-Assert.html)