Какова лучшая практика для модульного тестирования частных методов в .NET? - PullRequest
4 голосов
/ 23 февраля 2011

Недавно, чтобы реализовать модульное тестирование для частного метода класса, я использовал PrivateObject , создавая приватные методы доступа вместо использования Reflection , к которому я получил следующий комментарий к коду:

"Моя главная проблема с Private Object - использование объекта [] в конструкторе. Он заменяет строгую типизацию, принудительно установленную компилятором, на обнаружение ошибок во время выполнения в стиле JavaScript. Следовательно, лично я бы не рекомендовал это."

Этот комментарий, приведенный выше, смутил меня, так как, согласно моему пониманию, Reflection также требуется object[] для вызова любого метода. Пожалуйста, помогите мне понять, каков наилучший подход.

Ответы [ 4 ]

6 голосов
/ 23 февраля 2011
  • Вы можете использовать специальные классы, которые наследуют классы с закрытыми (теперь защищенными) методами и предоставляют открытые методы, которые вызывают невидимые извне защищенные методы.

Это называется Test Specific Subclass или TestСпециальное расширение в большой книге Рефакторинг кода теста http://xunitpatterns.com/

Более подробную информацию и идеи для тестирования частных методов вы можете прочитать здесь: http://xunitpatterns.com/Test-Specific%20Subclass.html

Это работает как

public TestClass : RealClass
{
    public int  CallHiddenCalculate()
    {
        return  Calculate(); // Calculate is now protected method that we expose for test purposes in this class
    }
}

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

  • Вы также можете использовать условную компиляцию для атрибута видимости, как показано ниже
    #if DEBUG
        public
    #else
        private
    #endif

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

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

Что касается маркировкизакрытые методы как внутренние и имеющие тестовую сборку, видят, что внутренние методы плохи по многим причинам

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

, и я думаю, что есть и другие, но они наиболее важны

4 голосов
/ 23 февраля 2011

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

Если вам ДЕЙСТВИТЕЛЬНО нужно выставить «приватные» элементы для модульного тестирования, пометьте их как внутренние и сделайте их доступными через атрибут InternalsVisibleTo. Это некрасиво, но работает, и позже вы можете не допустить его в свою сборку с помощью условной компиляции.

2 голосов
/ 23 февраля 2011

Вы правы в том, что использование отражения имеет почти те же недостатки, что и использование шаблона PrivateObject.Лучшее решение состоит в том, чтобы не пытаться специально тестировать частные методы.

0 голосов
/ 23 февраля 2011

В случае, если вы используете Gallio / MbUnit среду тестирования, вы можете рассмотреть встроенный Зеркало API.

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

...