Поблочное тестирование частный код [дубликат]

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

Эта статья начинает обсуждать это:

http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html

15
задан Ian Boyd 29 September 2010 в 18:31
поделиться

11 ответов

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

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

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

MyClass obj = new MyClass();
MethodInfo methodInfo = obj.GetType().GetMethod("MethodName", BindingFlags.Instance | BindingFlags.NonPublic);
object result = methodInfo.Invoke(obj, new object[] { "asdf", 1, 2 });
// assert your expected result against the one above
15
ответ дан 1 December 2019 в 01:30
поделиться

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

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

0
ответ дан 1 December 2019 в 01:30
поделиться

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

0
ответ дан 1 December 2019 в 01:30
поделиться

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

Теперь в случае обратных вызовов, Это отличный пример того, как публичное использование частной собственности может значительно упростить написание и сопровождение тестов. Например, если класс A передает обратный вызов классу B, я сделаю этот обратный вызов общедоступным свойством класса A. Один тест для класса A использует реализацию-заглушку для B, которая записывает переданный обратный вызов. Затем тест проверяет обратный вызов передается B при соответствующих условиях. Затем отдельный тест для класса A может вызвать обратный вызов напрямую, чтобы убедиться, что он имеет соответствующие побочные эффекты.

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

Я знаю, это не красиво, но я думаю, что работает хорошо.

1
ответ дан 1 December 2019 в 01:30
поделиться

Будут ли работать файлы средств доступа? http://msdn.microsoft.com/en-us/library/bb514191.aspx Я никогда не работал с ними напрямую, но знаю, что мой коллега использовал их для тестирования частных методов в некоторых Windows Forms.

1
ответ дан 1 December 2019 в 01:30
поделиться

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

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

Например, 2 я бы посмотрел на запуск события, чтобы проверить обработчик.

Пример 3 - это пример шаблона шаблона, который существует на других языках. Я видел два способа сделать это:

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

  2. Снова расширите класс дополнительными хуками, которые позволяют напрямую вызывать защищенные методы.

0
ответ дан 1 December 2019 в 01:30
поделиться

На самом деле необходимо учитывать только два случая:

  1. частный код вызывается прямо или косвенно из открытого кода и
  2. частный код не ] вызывается из открытого кода.

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

Ergo: нет необходимости явно тестировать частный код.

Обратите внимание, что когда вы выполняете TDD, это невозможно для существования непроверенного частного кода. Потому что, когда вы выполняете TDD, единственный способ появления частного кода - это рефакторинг Extract {Method | Class | ...} из открытого кода. И рефакторинги, по определению, сохранение поведения и, следовательно, сохранение тестового покрытия. И единственный способ появления общедоступного кода - это результат неудачного теста. Если общедоступный код может отображаться как уже протестированный код только в результате неудачного теста, а частный код может появиться только в результате извлечения из общедоступного кода посредством рефакторинга с сохранением поведения, отсюда следует, что непроверенный частный код никогда не может появиться.

4
ответ дан 1 December 2019 в 01:30
поделиться

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

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

Если ваш «отдельный класс для тестирования» находится в той же сборке, вы можете использовать internal вместо private. Это открывает доступ к внутренним методам для вашего кода, но эти методы не будут доступны для кода не в вашей сборке.

РЕДАКТИРОВАТЬ: поиск SO по этой теме Я наткнулся на этот вопрос . Ответ, получивший наибольшее количество голосов, аналогичен моему ответу.

3
ответ дан 1 December 2019 в 01:30
поделиться

у нас есть цикломатическое правило, которое гласит что ни один метод не должен иметь цикломатическая сложность больше 5

Мне нравится это правило.

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

Если у вас есть частные методы со сложной логикой, рассмотрите возможность их рефакторинга в отдельный класс. Это также может помочь снизить цикломатическую сложность. Другой вариант - сделать метод внутренним и использовать InternalsVisibleTo (упомянутый в одной из ссылок в ответе Криса).

Уловки, как правило, возникают, когда у вас есть внешние зависимости, на которые ссылаются в частных методах. В большинстве случаев вы можете использовать такие методы, как Внедрение зависимостей , чтобы разъединить ваши классы. Для вашего примера со сторонней структурой это может быть сложно. Я' Я попробую сначала провести рефакторинг проекта, чтобы отделить сторонние зависимости. Если это невозможно, рассмотрите возможность использования Typemock Isolator . Я не использовал его, но его ключевая особенность - возможность "имитировать" частные, статические методы и т. Д.

Классы - это черные ящики. Протестируйте их таким образом.

РЕДАКТИРОВАТЬ: Я постараюсь ответить на комментарий Джейсона к моему ответу и редактирование исходного вопроса. Во-первых, я думаю, что SRP подталкивает к большему количеству классов, а не от них. Да, лучше избегать классов помощников швейцарской армии. Но как насчет класса, предназначенного для обработки асинхронных операций? Или класс поиска данных? Являются ли они частью ответственности исходного класса или они могут быть разделены?

Например, предположим, что вы перемещаете эту логику в другой класс (который может быть внутренним). Этот класс реализует асинхронный шаблон проектирования , который позволяет вызывающей стороне выбирать, будет ли метод вызываться синхронно или асинхронно. Модульные или интеграционные тесты написаны для синхронного метода. Асинхронные вызовы используют стандартный шаблон и имеют низкую сложность; мы их не тестируем (кроме приемочных испытаний). Если асинхронный класс является внутренним, используйте InternalsVisibleTo для его тестирования.

7
ответ дан 1 December 2019 в 01:30
поделиться

Несколько замечаний от специалиста по TDD, который возился с C #:

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

2) Эти небольшие вспомогательные методы могут более точно принадлежать какому-то другому классу. Ищите зависть к особенностям. То, что может быть неразумным в качестве частного члена исходного класса (в котором вы его нашли), может быть разумным публичным методом класса, которому он завидует. Протестируйте их в новом классе как открытые члены.

3) Если вы исследуете несколько небольших частных методов, вы можете обнаружить, что они связаны. Они могут представлять меньший класс интересов, отдельный от исходного класса. Если так, этот класс может иметь все общедоступные методы, но либо храниться как частный член исходного класса, либо, возможно, создаваться и уничтожаться в функциях. Протестируйте их в новом классе как публичные члены.

4) Вы можете унаследовать "Testable" класс от оригинала, в котором тривиальная задача - создать новый общедоступный метод, который ничего не делает, кроме вызова старого частного метода. . Тестируемый класс является частью тестовой среды, а не производственного кода, поэтому иметь специальный доступ - это здорово. Протестируйте его в тестовой среде, как если бы он был общедоступным.

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

Протестируйте их в новом классе как публичные члены.

4) Вы можете унаследовать «Testable» класс от оригинала, в котором тривиальная задача - создать новый публичный метод, который ничего не делает, кроме вызова старого частного метода. . Тестируемый класс является частью тестовой среды, а не производственного кода, поэтому иметь специальный доступ - это здорово. Протестируйте его в тестовой среде, как если бы он был общедоступным.

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

Протестируйте их в новом классе как публичные члены.

4) Вы можете унаследовать «Testable» класс от оригинала, в котором тривиальная задача - создать новый публичный метод, который ничего не делает, кроме вызова старого частного метода. . Тестируемый класс является частью тестовой среды, а не производственного кода, поэтому иметь специальный доступ - это здорово. Протестируйте его в тестовой среде, как если бы он был общедоступным.

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

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

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

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

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

2
ответ дан 1 December 2019 в 01:30
поделиться

Здесь есть несколько отличных ответов, и я в основном согласен с неоднократными советами по созданию новых классов. Однако для вашего Примера 3 существует хитрый и простой прием:

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

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

2
ответ дан 1 December 2019 в 01:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: