Тестирование, если коллекция содержит объекты на основе определенного свойства

Я использую NUnit 2.5.7. Я хочу проверить, содержит ли набор пользовательских объектов определенного класса определенные объекты на основе одного из свойств класса.

например. надуманный пример...

public class Person
{
    public string Name { get; set; }

    public Person(string name)
    {
        Name = name;
    }
}

// ...

public List<Person> GetFavouritePeople()
{
   List<Person> favouritePeople = new List<Person>();
   favouritePeople.Add(new Person("joe"));
   favouritePeople.Add(new Person("fred"));
   favouritePeople.Add(new Person("jenny"));

   return favouritePeople;
}

// ... 

[Test]
public GetFavouritePeople()
{
    List<Person> people = GetFavouritePeople();

    // What I'd like to test, but not sure how to do it...
    Assert.Contains(Name="joe", people);
    Assert.Contains(Name="fred", people);
    Assert.Contains(Name="jenny", people);
}

Хотя в этом примере это было бы достаточно просто, я не хочу создавать mock-объекты для каждого Person и использовать их в утверждении... Я просто хочу проверить на основе определенного свойства (Name в этом примере. )

Ответ 1

Вы можете использовать LINQ:

Assert.That(people.Any(p => p.Name == "joe"));

или, если вы хотите четко указать, что есть ровно один человек с каждым именем:

Assert.That(people.Count(p => p.Name == "joe"), Is.EqualTo(1));

Если вы хотите получить более качественное сообщение об ошибке, чем "Assertion failed, expected true, false", вы можете создать свой собственный метод assert.

Для нескольких утверждений, связанных с коллекцией, CollectionAssert очень полезен - например, он позволяет вам проверить, содержат ли две коллекции одни и те же элементы, независимо от их порядка. Итак, еще одна возможность:

CollectionAssert.AreEquivalent(new[] {"joe", "fred", "jenny"}, people.Select(p => p.Name).ToList());

Обратите внимание, что CollectionAssert.AreEquivalent() немного придирчиво относится к типам, которые он принимает (даже если подпись принимает IEnumerable). Обычно я обертываю его другим методом, который вызывает ToList() по обоим параметрам перед вызовом CollectionAssert.AreEquivalent().

Ответ 2

Вы можете использовать Linq Intersect(), чтобы определить, находятся ли все ожидаемые элементы в списке вашего тестирования против, даже если список содержит другие элементы, которые вы не тестируете:

[Test]
public void TestFavouritePeople()
{
    var people = GetFavouritePeople();
    var names = people.Select(p => p.Name);

    var expectedNames = new[] {"joe", "fred", "jenny"};
    var actualNames = names.Intersect(expectedNames);

    CollectionAssert.AreEquivalent(expectedNames, actualNames);
}

Для NUnit 3.0 и выше вы можете использовать Is.SupersetOf():

[Test]
public void TestFavouritePeople()
{
    var people = GetFavouritePeople();
    var names = people.Select(p => p.Name);

    var expectedNames = new[] {"joe", "fred", "jienny"};
    var actualNames = names;

    Assert.That(actualNames, Is.SupersetOf(expectedNames)); 
}