Как писать модульные тесты для частных методов

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

Я не хочу делать этот метод общедоступным, поскольку этот вопрос подчеркивает:

Создание открытого частного метода для его модульного тестирования. ..хорошая идея?

Мой вопрос: каковы различные способы тестирования частных методов, какой из них я должен отдать предпочтение и почему?

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

Если этот вопрос считается дубликатом Как вы проводите модульное тестирование частных методов? Я добавлю туда свой комментарий и попрошу обновления, посоветуйте, пожалуйста.


person Mr. Mr.    schedule 30.05.2013    source источник
comment
Используйте технику отражения   -  person user1283633    schedule 30.05.2013
comment
посмотрите на этот bugsquash.blogspot.it/2009 / 05 /   -  person Fabio Marcolini    schedule 30.05.2013
comment
@FabioMarcolini выглядит интересно, посмотрю внимательнее.   -  person Mr. Mr.    schedule 30.05.2013
comment
В официальном блоге MSDN был похожий метод, в котором объяснялось, как получить доступ к частному с помощью некоторого объекта в пространстве имен модульного теста, но я его не нашел.   -  person Fabio Marcolini    schedule 30.05.2013
comment
и вот это blogs.msdn.com/b/atverma/archive/2010/09/17/   -  person Fabio Marcolini    schedule 30.05.2013
comment
@FabioMarcolini Спасибо за ссылку. Я изучаю динамический подход из первой ссылки.   -  person Mr. Mr.    schedule 30.05.2013


Ответы (7)


Вы хотите иметь возможность вызвать свой частный метод в тесте и посмотреть, как он работает?

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

Изменить: поскольку этот ответ все еще привлекает некоторый трафик, я делюсь этой ссылкой. Это сообщение в блоге было создано примерно через 4 года после того, как я опубликовал свой ответ: https://enterprisecraftsmanship.com/posts/unit-testing-private-methods/.

person Piotr Perak    schedule 30.05.2013
comment
+1 Да, я согласен, мне не очень нравится тестировать частный метод изолированно из-за хрупкости, которую он привнесет в будущем, если вызывающий метод каким-то образом изменится, в этом случае нет тестов, охватывающих это, но я думаю, что я буду do на самом деле наследует и вызывает базовые реализации, проходящие через полный поток, хотя я буду имитировать довольно много внутренних компонентов и позволю тесту развиваться по мере появления изменений в будущих версиях. - person Mr. Mr.; 30.05.2013
comment
В конце концов, я унаследовал от класса, который хотел протестировать, и переопределил свой частный метод, захватил входные и выходные данные и использовал их в своем тесте. - person Mr. Mr.; 03.06.2013
comment
Есть даже название для того, что вы сделали - Извлечь и переопределить - person Piotr Perak; 03.06.2013
comment
Да: taswar.zeytinsoft.com/2009/03 / 08 / - person Mr. Mr.; 03.06.2013
comment
Частные методы - это совершенно допустимые тестируемые объекты, тестирование - это не уровень доступа, уровни доступа - это только языковая конструкция, тестирование - это утверждение функциональности, невозможность доступа к функциональности является ограничением фреймворка. Прочтите эти комментарии, чтобы узнать больше stackoverflow.com/a/249853/1441011 - person Tjad Clark; 05.02.2018
comment
Кроме того, из производных классов доступны только защищенные методы, но не частные методы. - person Tjad Clark; 05.02.2018
comment
@TjadClark, вы правы в доступности частных / защищенных методов из производного класса. Но это только ваше мнение, что есть смысл тестировать частные методы. - person Piotr Perak; 05.02.2018
comment
Дело в том, что мне нужно протестировать существующий код. Код использует частный метод, который (все в одном методе) получает отчет, изменяет / преобразует данные отчета, а затем обновляет базу данных. Плохой, ПЛОХОЙ дизайн, но у меня нет ни времени, ни доброй воли, чтобы реорганизовать его так, как нужно. К счастью, MS, похоже, понимает, что иногда приходится тестировать частные методы, и предоставляет для этого класс PrivateObject. - person EoRaptor013; 11.07.2019

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

Возможно, у вас есть возможность реорганизовать код, чтобы частные методы стали общедоступными методами какого-то другого класса (ов). Хорошим примером является класс, который планирует некоторую работу по таймеру для обработки в более позднее время. Метод работы, вероятно, будет реализован как частный метод, что затруднит тестирование простым способом без планирования таймера и ожидания, пока он выполнит метод работы. Не идеально для теста, где время выполнения должно быть очень быстрым. Простой способ обойти это - разделить рабочий код планирования на два отдельных класса. Затем частный метод работы становится общедоступным методом класса Worker, что упрощает его тестирование. Хотя разделение кода планирования и рабочего кода означает, что вам будет сложно достичь 100% покрытия, вы, по крайней мере, покроете рабочий код. Один из способов решения проблемы - использовать что-то вроде Quartz.net для реализации класса планировщика, чтобы вы могли легко модульно тестировать планировщик, а также рабочий код.

person Jack Hughes    schedule 30.05.2013
comment
+1 Да, вы правы, это может указывать на какой-то недостаток дизайна, но я считаю, что потребуется много работы, чтобы написать тест для уже существующей части функциональности, что как бы выходит за рамки текущего изменения, которое я изготовление. Я действительно хочу полностью проверить это, но не могу сделать это прямо сейчас. - person Mr. Mr.; 30.05.2013
comment
Ваш вклад здесь на самом деле то, с чем я согласен, поэтому побудил бы людей проголосовать за этот ответ, чтобы он получил заслуженную известность, хотя в моем конкретном случае было невозможно следовать рекомендациям. - person Mr. Mr.; 03.06.2013

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

Я бы избегал принятого ответа.

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

Я вижу два немедленных варианта:

  • Размышление, чтобы увидеть метод, своего рода взлом, но, по крайней мере, вы можете провести какой-то тест. Это также, вероятно, самый простой способ быстро приступить к работе.
  • Абстрагируйте поведение частного метода, используя что-то вроде шаблона стратегии, и внедрите поведение в сам объект (или попросите объект внутри new выполнить соответствующую стратегию вручную). Затем этот отдельный элемент стратегии можно протестировать независимо.

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

person Adam Houldsworth    schedule 30.05.2013
comment
+1 Спасибо за ваш вклад, я тоже думал об отражении, но надеялся избежать этого, если возможно, поскольку я подозреваю, что это потребует значительных усилий? - person Mr. Mr.; 30.05.2013
comment
@Monkieboy Ничего особенного, если вы делаете это только для небольшой горстки предметов. Конечно, код более подробный и не является строго типизированным или чем-то еще, но вы можете рассматривать это как компромисс. - person Adam Houldsworth; 30.05.2013

В VS 2005, 2008 и 2010 у вас может быть частный аксессор. Вы щелкаете правой кнопкой мыши частную функцию и выбираете «Создать частный аксессуар» ...

В VS 2012 эта функция как-то пропала. Единственный удобный способ - использовать PrivateObject. Вы можете проверить MSDN для примеров использования PrivateObject.

person ZZZ    schedule 30.05.2013

Используйте отражение. Если вы не хотите самостоятельно возиться с отражением, вы можете использовать класс Microsoft PrivateObject, расположенный в Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll. Но есть проблемы при взаимодействии MSTest и NUnit - Используете и MSTest, и NUnit?

person nikita    schedule 30.05.2013

Если вы используете VS 2005 или выше, выполните следующие действия.

  1. Откройте файл исходного кода, содержащий частный метод.
  2. Щелкните частный метод правой кнопкой мыши и выберите «Создать модульные тесты». Откроется диалоговое окно «Создание модульных тестов». В видимой древовидной структуре установлен флажок только для частного метода.
  3. (Необязательно) В диалоговом окне «Создание модульных тестов» вы можете изменить выходной проект. Вы также можете нажать «Настройки», чтобы изменить способ создания модульных тестов.
  4. Щелкните ОК. Это создает новый файл с именем VSCodeGenAccessors, который содержит специальные методы доступа, которые извлекают значения частных сущностей в тестируемом классе. Вы можете увидеть новый файл, отображаемый в обозревателе решений в папке тестового проекта. Если в вашем тестовом проекте до этого момента не было модульных тестов, также создается файл исходного кода для размещения модульных тестов. Как и файл, содержащий частные методы доступа, файл, содержащий модульные тесты, также отображается в вашем тестовом проекте в обозревателе решений.
  5. Откройте файл, содержащий ваши модульные тесты, и перейдите к тесту для частного метода. Найдите утверждения, отмеченные // TODO: comments, и завершите их, следуя инструкциям в комментариях. Это помогает тесту давать более точные результаты.

Для получения дополнительной информации см. это

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

person Priyang    schedule 21.02.2014

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

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

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

person Serguei Fedorov    schedule 05.03.2015