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

StackOverflow https://stackoverflow.com/questions/2267248

Вопрос

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

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

Что делать, если вы также хотите иметь возможность модульного тестирования Foo?Возможно ли внедрение зависимостей?Означает ли это, что Bar и Foo слишком тесно связаны (хотя зависимость односторонняя) и что такая ситуация никогда не является приемлемой?

Это было полезно?

Решение

[Отказ от ответственности:Я работаю в Типомок]

У вас есть три альтернативы:

  1. Создайте внутренний метод, который устанавливает класс Bar. Используя InternalVisibleTo в файле AssemblyInf.cs, вы можете разрешить своим тестам устанавливать этот класс.
  2. Используйте DI для внедрения класса Bar, во время теста измените этот класс на фиктивный или поддельный.
  3. Используйте платформу Faking/Mocking, например Typemock Isolator (.NET), которая позволяет вам устанавливать ложное поведение для объектов, созданных в другом классе, используя Isolate.Swap.NextInstance<Bar>.With(fakeBar);

Другие советы

Вы никогда не захотите скрывать зависимости, если можете.

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

Если это непрактично (т. е. вы имеете дело с чужими классами), Список Дрора очень хорошо.

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

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

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

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

Есть ли причина, по которой экстернализация зависимости нежелательна?Что насчет этого объекта освобождает его от внедрения зависимостей, как и любой другой?

Редактировать:

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top