开发者

Application Variable in WPF While Maintaining Testability

开发者 https://www.devze.com 2022-12-20 19:14 出处:网络
I开发者_开发技巧 am working on a WPF application, using the MVVM Pattern. Each ViewModel will need access to a security object, that essentially provides information about the rights the user has.Bec

I开发者_开发技巧 am working on a WPF application, using the MVVM Pattern.

Each ViewModel will need access to a security object, that essentially provides information about the rights the user has. Because this object only needs to be populated once at start up, and because populating it is (at least potentially) expensive, I want to keep it in state for the lifetime of the application.

I can make it a static variable in App, which would make it available to the whole application (at least that's my understanding). This would make my ViewModel implementations very difficult to test, since the App.SecurityObject call would be inline in each ViewModel. I would have to make sure App was available for each test and mock the App.SecurityObject call (I'm not even sure this would work, actually).

We are using StructureMap, so I could create a SecurityObjectProvider and configure a it with a Singleton lifecycle in the container, and simply make it part of every ViewModel constructor. The downside would be that (as I said) the provider would have to be part of every View Model constructor.

There are other, hacky workarounds I can think of, but they would involve creating methods (perhaps in the View Model base class) that would allow injecting the security object after instantiation for testing purpose only. I usually try to avoid this kind "for testing only" code.

It seems like this would be a common problem , but I can't find any SO questions that are completely on point.


Security concerns are often best adressed by Thread.CurrentPrincipal. If it's at all possible to fit your security concerns into that model (calling Principal.IsInRole and so on) that is by far the desirable solution.

It's pretty easy to unit test because you just need to set Thread.CurrentPrincipal before invoking the SUT and then make sure you revert it to its original value in the Fixture Teardown phase.

If Thread.CurrentPrincipal doesn't suit your need, I would suggest either an injected dependency or a Decorator that handles security. Security is often a Cross-Cutting Concern, so it is often preferable to handle it as declaratively as possible. In other words, if you can model it by Guards and Assertions, you don't need to actively call it, and you would be able to use a more AOP-like approach (such as a Decorator).

If that's not possible either, you can model it as an Ambient Context. This may look a bit like the Service Locator anti-pattern, but the difference is that it's strongly typed and has a Local Default that ensures that it never throws NullReferenceExceptions or their like because it protects its invariants.


The service locator pattern might help you out. You still implement the functionality as a service, but you have your VMs go through a static class to obtain the service, rather than have it injected:

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

When running unit tests, you can configure your service locator to return mocks/stubs.


I think I would use some kind of Service Locator to get object. And in tests I would mock it out.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号