WPF中的应用程序变量同时保持可测试性

时间:2010-02-18 17:11:19

标签: wpf mvvm dependency-injection

我正在使用MVVM模式开发WPF应用程序。

每个ViewModel都需要访问一个安全对象,它实质上提供了有关用户权限的信息。因为这个对象只需要在启动时填充一次,并且因为填充它(至少可能)是昂贵的,所以我希望在应用程序的生命周期内将其保持在状态。

我可以在App中使它成为静态变量,这将使整个应用程序可用(至少这是我的理解)。这将使我的ViewModel实现很难测试,因为App.SecurityObject调用将在每个ViewModel中内联。我必须确保App可用于每个测试并模拟App.SecurityObject调用(我甚至不确定这会起作用,实际上)。

我们正在使用StructureMap,因此我可以创建一个SecurityObjectProvider并在容器中配置一个Singleton生命周期,并简单地将它作为每个ViewModel构造函数的一部分。缺点是(正如我所说),提供者必须成为每个View Model构造函数的一部分。

我还可以考虑其他一些hacky解决方法,但是它们会涉及创建方法(可能在View Model基类中),这些方法允许在实例化之后注入安全对象以仅用于测试目的。我通常会尽量避免这种“仅用于测试”的代码。

这似乎是一个常见的问题,但我找不到任何完全正确的问题。

3 个答案:

答案 0 :(得分:3)

Thread.CurrentPrincipal通常最能解决安全问题。如果完全可以将您的安全问题纳入该模型(调用Principal.IsInRole等),这是迄今为止理想的解决方案。

单元测试非常简单,因为您只需要在调用SUT之前设置Thread.CurrentPrincipal,然后确保将其恢复为Fixture Teardown阶段的原始值。

如果Thread.CurrentPrincipal不适合您的需要,我会建议注入依赖项或处理安全性的Decorator。安全性通常是交叉关注,因此通常最好尽可能以声明方式处理它。换句话说,如果您可以通过Guards和Assertions对其进行建模,则无需主动调用它,并且您将能够使用更强大的 AOP 类方法(例如Decorator)

如果这也不可能,您可以将其建模为Ambient Context。这可能看起来有点像Service Locator anti-pattern,但不同之处在于它是强类型的,并且具有 Local Default ,可确保它永远不会抛出NullReferenceExceptions或类似因素,因为它会保护其不变量。< / p>

答案 1 :(得分:2)

service locator模式可能会帮助你。您仍然将该功能实现为服务,但您让VM通过静态类来获取服务,而不是将其注入:

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

运行单元测试时,您可以配置服务定位器以返回模拟/存根。

答案 2 :(得分:0)

我想我会使用某种Service Locator来获取对象。在测试中我会嘲笑它。