Молодец!
Настоящие профессионалы не полагаются на случай, они стелют соломку заранее держат все под контролем.
Хочешь чтобы внутри, за публичным интерфейсом, тоже все было покрыто тестами?
Как и всегда, способов несколько. Есть получше, есть попроще. Поехали!
1. Делаем метод публичным
Нет приватного метода – нет проблемы. Можно еще комментарий к методу написать
// For tests only. Do not use directly.
Плюсы: очень просто.
Минусы: засоряется интерфейс, страдает инкапсуляция.
2. Делаем метод внутренним
То есть меняем модификатор доступа с private
на internal
. Комментарий из первого способа тут тоже сгодится. Получается метод, который доступен из любого места в пределах сборки.
А тестировать-то его как? Просто. Нужно добавить к сборке атрибут InternalsVisibleTo. Этот атрибут даст тестирующей сборке доступ ко всем internal методам и свойствам тестируемой сборки.
Не забудьте, что для функционирования атрибута InternalsVisibleTo
требуется, чтобы обе сборки (тестирующая и тестируемая) были одновременно подписаны строгим именем, либо одновременно не подписаны.
Плюсы: достаточно просто, остается контроль за тем, кто имеет доступ к внутренностям сборки.
Минусы: все равно засоряется интерфейс, все равно страдает инкапсуляция, появляются дополнительные условия (см. выше про подписывание), атрибут остается в релизной сборке.
3. Делаем метод защищенным
Вместо модификатора private
метод должен обзавестись модификатором protected
. В тестирующей сборке нужно будет сделать наследника от тестируемого класса и — вуаля! – доступ к методу получен.
Плюсы: достаточно просто, есть некоторый контроль за тем, кто имеет доступ к методу.
Минусы: все равно засоряется интерфейс, все равно страдает инкапсуляция, метод доступен всем, кто пожелает его унаследовать, класс с таким методом не может быть помечен закрытым для наследования (sealed).
4. Используем PrivateObject
Этот класс предоставляет Visual Studio Unit Testing Framework, так что если в проекте используется NUnit или еще что-то, то этот способ не подойдет.
С PrivateObject
все просто. Есть класс для тестирования:
public class ClassToTest
{
private string field;
private void PrintField()
{
Console.WriteLine(field);
}
}
Есть тестирующий класс:
[TestClass]
public class TestClass
{
[TestMethod]
public void TestPrivateMethod()
{
ClassToTest testedClass = new ClassToTest();
PrivateObject privateObject = new PrivateObject(testedClass);
privateObject.SetField("field", "Don't panic");
privateObject.Invoke("PrintField");
}
}
После выполнения теста в консоли будет строка Don't panic
. Всегда хороший совет, так ведь?
Плюсы: не требуется менять существующий код, достаточно просто.
Минусы: применимо только к Visual Studio Unit Testing Framework, при переименовании полей и методов тесты начнут падать.
5. Рефлексия нам поможет
Код будет подлиннее, чем в предыдущем способе, но жить можно.
Опять же, есть класс для тестирования:
public class ClassToTest
{
private string field;
private void PrintField()
{
Console.WriteLine(field);
}
}
В тесте нужно написать следующее:
ClassToTest obj = new ClassToTest();
Type t = typeof(ClassToTest);
FieldInfo f = t.GetField("field", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
f.SetValue(obj, "Don't panic");
t.InvokeMember("PrintField",
BindingFlags.InvokeMethod | BindingFlags.NonPublic |
BindingFlags.Public | BindingFlags.Instance,
null, obj, null);
В консоли снова должен появиться хороший совет.
Вышеприведенный код можно использовать в любых тестах. Хоть для NUnit, хоть для Visual Studio Unit Testing Framework, хоть для любой другой среды тестирования.
Плюсы: не требуется менять существующий код, достаточно просто, применимо для люой среды тестирования.
Минусы: без вспомогательного класса в тестах будут километры повторяющегося кода, при переименовании полей и методов тесты начнут падать.
Вместо заключения
Теперь, когда ты знаешь, как тестировать не-публичные методы, самое время задуматься: а надо ли их тестировать?
Аргументы «за»:
- Не-публичные методы могут содержать сложную логику, которую стоит проверять.
- Иногда использование приватных методов в тестах может уменьшить объем кода, необходимого для создания тестовых данных.
- Тестировать вообще нужно все. Чем больше строк кода покрыто тестами, тем лучше.
Аргументы «против»:
- Тестировать нужно поведение, а не реализацию. А значит, тестировать нужно только интерфейс класса (только публичные методы и свойства).
- Тесты для приватных методов мешают рефакторить код, а рефакторить код не менее важно, чем тестировать.
- Если метод приватный, то это не просто так. Это значит, что трогать его не надо.
Лично я играю за команду «против». Я думаю, что тестировать нужно только публичные методы и свойства.
This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Комментариев нет:
Отправить комментарий