Переменная приложения в WPF при сохранении тестируемости - PullRequest
3 голосов
/ 18 февраля 2010

Я работаю над приложением WPF, используя шаблон MVVM.

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

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

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

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

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

Ответы [ 3 ]

3 голосов
/ 19 февраля 2010

Вопросы безопасности часто лучше всего решаются Thread.CurrentPrincipal . Если это вообще возможно, чтобы вписать ваши проблемы безопасности в эту модель (вызывая Principal.IsInRole и т. Д.), Это, безусловно, желаемое решение.

Довольно легко выполнить модульное тестирование, потому что вам просто нужно установить Thread.CurrentPrincipal перед вызовом SUT , а затем убедиться, что вы вернули его к исходному значению в фазе Fixture Teardown .

Если Thread.CurrentPrincipal не подходит вам, я бы предложил либо внедренную зависимость, либо декоратор, который обрабатывает безопасность. Безопасность часто является сквозной проблемой , поэтому часто предпочтительнее обращаться с ней как можно более декларативно. Другими словами, если вы можете смоделировать его с помощью Guards and Assertions, вам не нужно активно вызывать его, и вы сможете использовать более AOP -подобный подход (такой как Decorator).

Если это также невозможно, вы можете смоделировать его как Окружающий контекст . Это может выглядеть немного как шаблон Service Locator , но разница в том, что он строго типизирован и имеет Local Default , который гарантирует, что он никогда не вызовет NullReferenceExceptions или им подобные, потому что он защищает свои инварианты.

2 голосов
/ 18 февраля 2010

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

var securityService = ServiceLocator.Resolve<ISecurityService>();

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

0 голосов
/ 18 февраля 2010

Я думаю, я бы использовал какой-то Service Locator , чтобы получить объект. И в тестах я бы издевался.

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