Подтвердить что ты не робот

Является ли хорошей практикой делать покрытие unit test для даже простых классов

Вот пример класса без какого-либо поведения. Поэтому вопрос в том, должен ли я делать unit test охват для него, поскольку я считаю его ненужным, поскольку он имеет какое-либо поведение в нем.

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Address { get; set; }
}

Мой результат покрытия кода жалуется, что я не сделал никакого покрытия для класса

4b9b3361

Ответ 1

Я никогда не пишу тесты для них. Нет теста для тестирования.

Если бы был какой-то нетривиальный поведенческий код (возможно, код проверки), я бы написал для него тест.

Ответ 2

Я нашел эту интересную статью из Martin Fowler:

Тестирование покрытия - полезный инструмент для поиска непроверенных частей кодовая. Тестовый охват мало полезен в качестве числового заявления о том, как хорошие ваши тесты.

===

Также эта интересная цитата из Наставник объектов:

Вероятно, это не обязательно, и если ваша цель - 100% -ное покрытие, youll сосредоточиться на этой цели, а не сосредоточиться на написании лучших тестов для поведение вашего кода.

Ответ 3

Я мог бы взять его или оставить. Но пока есть немного очевидной выгоды, вы были бы охвачены, если позже придет программист, преобразует их в традиционные свойства, поддерживаемые полями-членами, и пошатнул реализацию в тривиальном случае.

Но я лично на самом деле не беспокоился бы, поскольку мое время ограничено, и у меня есть более важные тесты для написания, которые обеспечат больший удар для моего доллара.

Ответ 4

Это не плохая идея... Скажем, например, вы разрабатываете бэкэнд для хранения этих данных в будущем (например, в базе данных). Вы можете заменить общие вызовы get; set; на дополнительные пользовательские функции. Наличие unit test гарантирует, что ваш код всегда будет реализован и что ошибки не будут введены при переходе.

Даже очень простой тест, который проверяет, чтобы вы могли создать объект, задать поля и прочитать те же значения, показывает, что вы выполняете код с ожидаемым поведением. Даже если это будет очевидно для вас, будущие разработчики этого кода будут иметь пример, чтобы использовать и гарантировать, что любые изменения соответствуют вашим первоначальным целям дизайна.

Я также смотрю на это так: в разработке теста мало что может быть вредно с некоторыми очень долгосрочными преимуществами. Это займет всего несколько минут вместо отслеживания проблемы, возникшей по линии.

Ответ 5

Альтернативный подход к этому вопросу: тот факт, что у вас нет покрытия по этому конкретному классу, намекает, что существует какой-то код, который использует этот класс, и этот код также не имеет тестового покрытия. Сначала я бы разрешил эту проблему и посмотрел, нужно ли больше тестов.

Что касается тестирования такого объекта только для данных: я бы определенно добавил явный тест, если этот объект является частью внешнего контракта библиотеки/единицы. Вы обещаете, что эти данные будут возвращены/использованы вашим кодом. Если нет проверки, подтверждающей, что вы можете изменить внутренности кода и изменить этот класс, вы нарушите обещание и ничего не остановите.

Ответ 6

Кент Бек в своем "Test-Driven Development by Example" перечисляет то, что вам нужно :

  • условными
  • петли
  • операции
  • полиморфизм

В вашем классе нет ни одного из них.

Это часто помогает задать себе вопрос: "Что я получу, если я наложу этот код на модульные тесты?". Если "указывает на некоторые показатели" - это единственный ответ, который вы можете придумать, вероятно, не стоит писать тесты для такого кода. Вы потратите время, произведете дополнительный код и ничего не получите (точки покрытия кода "имеют мало значения - по крайней мере, в этом контексте" ).

Кроме того, взгляните на эти два вопроса (они оба решают подобную проблему, и ответы в первую очередь решаются вокруг одного важного момента - [в большинстве случаев] всегда кто-то платит деньги за то, что вы делаете, и что кто-то может быть не очень взволнованный, зная, что вы проводите время, улучшая рейтинги, поскольку это то, что по сути есть):

Окончательный вывод? Я согласен с другими, говоря, что вы не должны тестировать такие классы.

Ответ 7

Если вы просто держите такие классы, как объекты передачи данных, можно утверждать, что вам не нужны модульные тесты для них. Однако, как только вы начнете добавлять поведение, вы должны написать соответствующие тесты.

Глядя на покрытие кода, которое может быть возвращено как часть вашего построенного процесса, может также помочь выявить недостающие тесты.

В качестве короткого ответа я бы сказал "да", для простых классов вы можете уйти без покрытия.

Ответ 8

Точка модульного тестирования заключается в том, чтобы сохранить ваш код "исправленным" таким образом, что если вы измените реализацию, вы это сделаете, зная, что вы ничего не сломали, или что если вы нарушите что-то, вы сразу же узнаете, что именно вы сломали.

Преимуществом этого является знание того, что ваш код, как он написан в настоящее время, делает то, что вы хотите, но это не (или необязательно) основная цель модульного тестирования. Модульное тестирование позволяет с уверенностью изменять код.

Если такой класс, как указано выше, не проверен модулем, тогда класс может быть разбит, не вызывая какого-либо теста. Например:.

public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get { return "Smith"; } set { FirstName = value; } }
    public Address Address { get; set; }
}

С помощью модульных тестов вы можете знать, что что-то вроде этого не произошло на всей вашей кодовой базе. (Возможно, это конкретный пример? Возможно, нет. Но что-то вроде этого очень возможно и в основном невозможно.)

С помощью всего лишь четырех простых модульных тестов вы можете сделать этот код "фиксированным", зная, что он не может изменить его поведение без сбоя теста *:

[TestMethod]
public void TestId() {
   var emp = new Employee { Id = 3 };
   Assert.AreEqual(3, emp.Id);
}

[TestMethod]
public void TestFirstName() {
   var emp = new Employee { FirstName = "asdf" };
   Assert.AreEqual("asdf", emp.FirstName);
}

[TestMethod]
public void TestLastName() {
   var emp = new Employee { LastName = "asdf" };
   Assert.AreEqual("asdf", emp.LastName);
}

[TestMethod]
public void TestAddress() {
   var address = new Address();
   var emp = new Employee { Address = address };
   Assert.AreEqual(address, emp.Address);
}

(* возможно, кроме случая сбоя сломанной реализации, имитирующего значения, которые вы используете для тестирования)

Я не буду реализовывать его здесь, но вы также можете использовать рефлексию для упрощения написания таких тестов. Например, вы можете построить что-то относительно легко, что позволит вам сделать следующее:

[TestClass]
public sealed TestEmployee {
   [TestMethod]
   public void TestSimpleProperties() {
      Assert.IsTrue(
         SimplePropertyTester.Create(
            new SimplePropertyTestCollection<Employee> {
               { emp => emp.Id, 3 },
               { emp => emp.FirstName, "asdf" },
               { emp => emp.LastName, "1234" },
               { emp => emp.Address, new Address() }
            }
         ).Test()
      );
   }
}

Вы теряете преимущество наличия каждого свойства в своем собственном тесте, но вы получаете возможность очень легко модифицировать набор тестов.

Вы также можете создать отдельный тестер с одним тестом для каждого unit test, а затем вы будете держать тесты отдельными, но это не так много отличается от того, как просто писать их вручную, и вы в конечном итоге пишете в основном ту же строку кода снова и снова.

Одна вещь, которую вы можете сделать, это поместить выражения Console.WriteLine в метод Test(), а затем вы сможете иметь некоторый текстовый вывод, чтобы посмотреть, чтобы определить проблему намного быстрее.

EDIT: На самом деле теперь я получил следующее:

[TestClass]
public sealed TestEmployee {
   [TestMethod]
   public void TestSimpleProperties() {
      var factory = SimplePropertyTestFactory.Create<Employee>();
      new SimplePropertyTestCollection<Employee> {
         factory.IntTest(emp => emp.ID),
         factory.StringTest(emp => emp.FirstName),
         factory.StringTest(emp => emp.LastName),
         factory.ReferenceTest(emp => emp.Address)
      }.Test();
   }
}