web-dev-qa-db-ja.com

Xunit.Assert.Collectionの問題-C#

私はクラスライブラリを持っています、それは次のモデルとメソッドが含まれています

モデル:

public class Employee {
    public int EmpId { get; set; }
    public string Name { get; set; }
}

方法:

public class EmployeeService {
    public List<Employee> GetEmployee() {
        return new List<Employee>() {
            new Employee() { EmpId = 1, Name = "John" },
            new Employee() { EmpId = 2, Name = "Albert John" },
            new Employee() { EmpId = 3, Name = "Emma" },
        }.Where(m => m.Name.Contains("John")).ToList();
    }
}

テスト方法があります

[TestMethod()]
public void GetEmployeeTest() {
    EmployeeService obj = new EmployeeService();
    var result = obj.GetEmployee();
    Xunit.Assert.Collection<Employee>(result, m => Xunit.Assert.Contains("John",m.Name));
}

例外メッセージが表示されました

Assert.Collection() Failure
Collection: [Employee { EmpId = 1, Name = "John" }, Employee { EmpId = 2, Name = "Albert John" }]
Expected item count: 1
Actual item count:   2

私の要件は、すべてのitems.Nameにサブ文字列「John」が含まれていることを確認することです。 Xunit.Assert.Collectionを使用して確認する方法をサポートしてください

11
user7784919

Assert.Collectionは各要素インスペクターを1回だけ使用するようです。したがって、テストでは、次のように機能します。

シーケンスresultに正確に2つの要素がある場合:

[Fact]
public void GetEmployeeTest()
{
    EmployeeService obj = new EmployeeService();
    var result = obj.GetEmployee();

    Assert.Collection(result, item => Assert.Contains("John", item.Name),
                              item => Assert.Contains("John", item.Name));
}

要素が多い場合Assert

Assert.All(result, item => Assert.Contains("John", item.Name));

期待する結果が得られるはずです。

32
Ayb4btu

これは、Ayb​​4btuの answer を拡張したもので、コレクション内のアイテムの順序に興味がない人向けです。

次のメソッドは元のXUnit実装に基づいており、非常に類似したインターフェイスを使用してテストできます。

public static class TestExpect
{
public static void CollectionContainsOnlyExpectedElements<T>(IEnumerable<T> collectionToTest, params Func<T, bool>[] inspectors)
{
    int expectedLength = inspectors.Length;
    T[] actual = collectionToTest.ToArray();
    int actualLength = actual.Length;

    if (actualLength != expectedLength)
        throw new CollectionException(collectionToTest, expectedLength, actualLength);

    List<Func<T, bool>> allInspectors = new List<Func<T, bool>>(inspectors);
    int index = -1;
    foreach (T elementToTest in actual)
    {
        try
        {
            index++;
            Func<T, bool> elementInspectorToRemove = null;
            foreach (Func<T, bool> elementInspector in allInspectors)
            {
                if (elementInspector.Invoke(elementToTest))
                {
                    elementInspectorToRemove = elementInspector;
                    break;
                }
            }

            if (elementInspectorToRemove != null)
                allInspectors.Remove(elementInspectorToRemove);
            else
                throw new CollectionException(collectionToTest, expectedLength, actualLength, index);
        }
        catch (Exception ex)
        {
            throw new CollectionException(collectionToTest, expectedLength, actualLength, index, ex);
        }
    }
}
}

ここでの違いは、コレクションの

 string[] collectionToTest = { "Bob", "Kate" };

次の行は両方ともCollectionExceptionを生成しません

 TestExpect.CollectionContainsOnlyExpectedElements(collectionToTest, x => x.Equals("Bob"), x => x.Equals("Kate"));
 TestExpect.CollectionContainsOnlyExpectedElements(collectionToTest, x => x.Equals("Kate"), x => x.Equals("Bob"));

一方、Assert.Collection-インスペクターのコレクションが順番に評価されるため、上記の2行のうち最初の行のみが機能します。

この方法を使用すると、パフォーマンスに影響が生じる可能性がありますが、かなり小さなサイズのコレクションのみをテストする場合(おそらく単体テストの場合)、違いに気付くことはありません。

2
Jay