Обложка канала

.NET Разработчик

Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин

.NET Разработчик

3 года назад
Открыть в
День 1510. #ЗаметкиНаПолях Создание Параметризованных Тестов в xUnit xUnit использует атрибуты для определения методов тестирования. Атрибут Fact определяет простой тест, а атрибут Theory определяет параметризованный тест. Допустим, у нас есть следующий тест, проверяющий, что парсер email корректно извлекает домен:
public void Should_Return_Domain(
 string email, string expectedDomain)
{
  var parser = new EmailParser();
  var domain = parser.GetDomain(email);
  Assert.Equal(domain, expectedDomain);
}

Рассмотрим 4 способа написания параметризованных тестов. 1. InlineData Простейший способ - вы предоставляете тестовые данные, передавая значения конструктору:
[Theory]
[InlineData("[email protected]", "test.com")]
[InlineData("[email protected]", "github.io")]
public void Should_Return_Domain(
 string email, string expectedDomain)
{ … }

Мы предоставляем два строковых значения для атрибута InlineData: аргумент тестируемого метода и ожидаемый результат. Можно указать атрибут InlineData столько раз, сколько будет тестовых случаев. Недостаток в том, что код становится очень многословным, когда у нас много тестовых случаев. И мы ограничены использованием только константных данных для параметров. 2. MemberData С помощью MemberData мы можем программно предоставить тестовые данные из статического свойства или члена типа:
[Theory]
[MemberData(nameof(EmailTestData))]
public void Should_Return_Domain(
 string email, string expectedDomain)
{ … }

public static IEnumerable<object[]> 
 EmailTestData => new List<object>
 {
   new object[] { "[email protected]", "test.com" },
   new object[] { "[email protected]", "github.io" }
 };

Вы указываете имя члена в атрибуте MemberData. Одно ограничение - свойство (или метод) должно возвращать IEnumerable<object[]>, поэтому строгой типизации не существует. 3. ClassData Позволяет извлечь тестовые данные в отдельный класс. Это полезно для организации тестовых данных отдельно от тестов и упрощает повторное использование. Вы загружаете тестовые данные из класса, который наследуется от IEnumerable<object[]> и реализует метод GetEnumerator:
[Theory]
[ClassData(typeof(EmailTestData))]
public void Should_Return_Domain(
 string email, string expectedDomain)
{ … }

public class EmailTestData : IEnumerable<object[]>
{
  public IEnumerable<object[]> GetEnumerator()
  {
    yield return new object[] { 
     "[email protected]", "test.com" };
    yield return new object[] { 
     "[email protected]", "github.io" };
  }
    
  IEnumerator IEnumerable.GetEnumerator() 
   => GetEnumerator();
};
Этот подход сложен, потому что нужно реализовать интерфейс IEnumerable. И мы всё ещё страдаем от отсутствия безопасности типов. 4. TheoryData Позволяет реализовать класс для тестовых данных, сохраняя при этом безопасность типов. Вот пример в сочетании с атрибутом ClassData, но его также можно использовать и с MemberData, возвращая TheoryData из свойства или метода:
[Theory]
[ClassData(typeof(EmailTestData))]
public void Should_Return_Domain(
 string email, string expectedDomain)
{ … }

public class EmailTestData :
 TheoryData<string, string>
{
  public EmailTestData()
  {
    Add("[email protected]", "test.com");
    Add("[email protected]", "github.io");
  }
};
TheoryData – обобщённый класс, который позволяет указывать типы для параметризованного теста. Вы просто вызываете метод Add в конструкторе, чтобы предоставить тестовые данные для одного тестового примера. А добавление дополнительных тестов сводится к многократному вызову метода Add. Источник: https://www.milanjovanovic.tech/blog/creating-data-driven-tests-with-xunit