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

Как unit test частные методы в BDD/TDD?

Я пытаюсь программировать в соответствии с Behavior Driven Development, в котором говорится, что ни одна строка кода не должна быть написана без письменного разрешения сначала сбой unit test.

Мой вопрос в том, как использовать BDD с частными методами?
Как я могу unit test приватные методы?
Есть ли лучшее решение, чем:
- сначала публиковать приватные методы, а затем сделать их частными когда я пишу публичный метод, который использует эти частные методы;
или
- в С#, делая все частные методы внутренними и используя InternalsVisibleTo атрибут.

4b9b3361

Ответ 1

Когда вы пишете сначала тест кода, вы пишете против открытого интерфейса. На данный момент нет личных методов.

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

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

Ответ 2

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

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

Ответ 3

Краткий ответ: Вы не проверяете частные методы.

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

Ответ 4

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

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

Если частный метод не вызывается из общедоступного метода, то почему он существует?

В вашем случае я сделаю следующее

* Write failing test for the public method
* Write public method that calls the private method that doesn't exist yet(test still fails as your class is incomplete
* Write the private method
* Test should now pass

Ответ 5

Короткий ответ. Вы не можете проверить частный метод.

Длинный ответ. Вы не можете проверить частный метод, но если вы склонны тестировать все, что он считает рефакторингом вашего кода. Существует два тривиальных подхода:

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

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

Проницаемый ответ: Ладно, поэтому я солгал. Вы можете протестировать частный метод с помощью некоторой магии отражения (некоторые инструменты TDD поддерживают тестирование частных методов). По моему опыту, это приводит к свернутым модульным испытаниям. Сложные модульные тесты приводят к худшему коду. Хуже код приводит к гневу. Гнев ведет к ненависти. Ненависть ведет к страданиям...

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

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

Ответ 6

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

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

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

Ответ 7

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

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

public class TestableClassToTest : ClassToTest
{
    public new void MethodToTest() 
    { 
        base.MethodToTest(); 
    } 
}

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

Ответ 8

Mbunit Reflector поможет вам в этом.

Reflector objectReflection = new Reflector(new ObjectWithprivateMethods());
objectReflection.InvokeMethod(AccessModifier.NonPublic,,"Add",1,6));

Сообщение в блоге об этом.

Ответ 10

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

Время рефакторирования:)

Обычно я отбрасываю внутреннюю сложность в класс-помощник. Однако проверьте метод "Особенность зависания" или "Неуместная близость". Там может быть лучшее место для жизни. С помощью методов расширения в .net теперь даже базовые типы могут быть хорошим кандидатом.

Удача

Ответ 11

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

Откажитесь от интерфейса при тестировании исходного класса. Теперь у вас должен быть открытый доступ к новому классу, который ранее был приватным методом.

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

Ответ 12

Я боролся с этим больше 1 месяца, но нашел ответ:

        var objectOfPrivateMethod = new ObjectOfPrivateMethod(); //yes here is contructor
        object[] arguments = {  }; // here as Object you provide arguments

        var extractedPrivateMethod = typeof(ObjectOfPrivateMethod).GetMethod("Name_Of_Private_Method", BindingFlags.NonPublic|BindingFlags.Static); //if fails returns null. delete flag static if it not static. Returns your method as an object.
        Assert.AreNotEqual(null, extractedPrivateMethod, "Mathod does not exist"); // good to catch if even exists.

        object result = extractedPrivateMethod.Invoke(null, arguments); // here as object you'll get return value of your function. change null for object of class where is method, if your method is not static 

это все.