Есть ли что-то неправильное в размещении тестовых методов в том же классе, который вы тестируете?

#c# #unit-testing #nunit

#c# #модульное тестирование #nunit

Вопрос:

Есть ли что-то неправильное в размещении тестовых методов в том же классе, что и тестируемый вами класс?

Поэтому добавьте атрибут [TestFixture] к каждому классу и используйте метод [Test] наряду с реальными методами.

Мне нравится идея. Хранит все в одном месте.

Но каковы, если таковые имеются, недостатки этого?

/ Я использую Nunit и c #.

Комментарии:

1. Если вы действительно хотите протестировать частные методы, пометьте их как внутренние и используйте InternalsVisibleTo , чтобы разрешить вашим тестовым методам, которые ВСЕ еще находятся в другой сборке, вызывать их. Это полезно для тестирования белого ящика.

Ответ №1:

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

  • Наличие тестов в отдельной сборке помогает гарантировать, что у вас есть полезный API, поскольку они не могут обманывать с помощью конструкций private / protected . Вместо этого они вынуждены проходить через общедоступные точки API
  • Наличие тестов в той же сборке означает, что ваш производственный код также включает ваш тестовый код. Нет причин отправлять код заказчику, который они на самом деле не будут использовать
  • Заставляет производственный код принимать зависимости от сборок, которые им не нужны (Nunit, xunit и т.д.)
  • Многие платформы тестирования требуют, чтобы тестовые методы были общедоступными, следовательно, это выводит тесты на общедоступную поверхность вашего API.
  • Наличие их в одной сборке открывает дверь для случайного вызова производственного кода в тестовый код и, следовательно, в производственных средах появляются забавные утверждения

Комментарии:

1. Ничего, кроме веских причин. для этого. Помимо причины всех причин: разделение проблем.

Ответ №2:

Этот подход раздражает мою душу.

Я думаю, что гораздо разумнее хранить ваш тестовый код отдельно от вашего производственного кода. Много причин:

  • Теоретически, вы должны проводить тестирование в интерфейсе вашего кода и не иметь доступа к таким вещам, как закрытые элементы за кулисами.
  • Организация — наличие всех ваших тестов в отдельном проекте означает, что ваше основное приложение не будет загромождено тестовым кодом.
  • Это увеличило бы размер ваших результатов.
  • Размещение всего в одном месте затрудняет одновременную работу команды над кодовой базой (один человек над тестами, другой над кодом и т.д.).

Больше всего:

Это просто кажется / пахнет неправильно.

Комментарии:

1. Согласен. Лучше, чем мой ответ 🙂

Ответ №3:

ДА. Это нарушило бы принцип единой ответственности. Это снизит читаемость. Вы добавляете зависимость к своей платформе тестирования.

Ответ №4:

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

Комментарии:

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

2. Если вы проводите модульное тестирование только отладочных сборок, у вас уже есть проблема… Кроме того, если вы проводите модульное тестирование с использованием частных переменных, то многие скажут, что ваши тесты тестируют не то, что нужно.

Ответ №5:

Недостатки?

Технически в ваших классах будет больше методов, чем им нужно для использования в производственной среде. У вас также будут ссылки на NUnit, которые вам не нужны в производственной среде.

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

Ответ №6:

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

Более философским недостатком является то, что, хотя вы действительно сохраняете все вместе, вам не удается отделить проблемы самого кода (бизнес-логику) от проблем обеспечения качества (убедиться, что он работает правильно). Попробуйте подумать о своем коде с точки зрения единой ответственности за каждый класс / файл и посмотрите, к чему это вас приведет.

Ответ №7:

Вы не хотите использовать ярлыки.

Вы не хотите тестировать частные методы. Вы особенно не хотите использовать частные методы в качестве вспомогательных методов для ваших модульных тестов (т. Е. Повторно использовать их в своих тестах).

Гораздо приятнее группировать тестовые классы в тестовых проектах. Тогда они не влияют на тестируемый код, и гораздо проще вести обзор того, какой код у вас есть.

Таким же образом вы не смешиваете пользовательский интерфейс и код бизнес-логики.

Поэтому, пожалуйста, пожалуйста, очень пожалуйста, не смешивайте тесты с их тестируемыми объектами!

Ответ №8:

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

И использование констант трассировки для их условной сборки в этом случае становится действительно некрасивым. Например, одно условие для атрибута test fixture и по крайней мере одно для метода или группы методов.

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

Ответ №9:

Чтобы добавить свои два цента:

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

Однако, в общем, когда вы разрабатываете «с учетом тестирования», вы можете спроектировать свою реализацию так, чтобы она также тестировалась. Например, вы можете изначально спроектировать функцию / метод для использования переменной класса. Однако, если вы хотите протестировать функциональность этого метода, вы можете спроектировать его так, чтобы значение переменной класса «передавалось» в качестве параметра функции.

Теперь ваш метод функционален и поддается тестированию, то есть функциональному тестированию.

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

Я надеюсь, это поможет. Эта вики-страница дает хороший обзор тестирования в программировании в целом: http://en.wikipedia.org/wiki/Software_testing

Комментарии:

1. Обратите внимание, что в моем примере вы не увеличили бы свою кодовую базу для соответствующего класса. Вы бы просто разработали его с учетом тестирования, и в этом суть моего подхода.

Ответ №10:

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

Если вы хотите, чтобы ваши тесты соответствовали вашему классу, просто поместите их в тот же файл:

 public class Foo : IFoo
{
    ...
}

[TestFixture]
public class Foo_Tests
{
    ...
}
  

Комментарии:

1. Лучше, но они все равно будут находиться в одной сборке и по-прежнему будут вызывать зависимость тестовой среды, раздувать размер сборки, препятствовать параллельной разработке и т. Д