如何使用ViewModelLocator进行单元测试

5
我将使用Autofac创建一个自定义的视图模型定位器,并像通常一样通过App.xaml进行设置。我的问题是如何进行单元测试?每次尝试测试初始化视图的方法时都会出现错误。
在我的app.xaml中:
<desktop:ViewModelLocator xmlns:local="clr-namespace:MyProject.Desktop" x:Key="ViewModelLocator" />

在每个视图中:
DataContext="{Binding MyFirstViewModel, Source={StaticResource ViewModelLocator}}"

单元测试错误:

{"Cannot find resource named 'ViewModelLocator'. Resource names are case sensitive."}

我理解为什么会出现这种情况,因为在单元测试时,实际的应用程序实例并不存在,那么有什么好的解决方法呢?

ViewModelLocator 代码:

/// <summary>
/// Autofac object container
/// </summary>
private readonly IContainer objectContainer;

#region Constructor

/// <summary>
/// Constructor for view model locator
/// </summary>
public ViewModelLocator()
{
    objectContainer = App.ObjectContainer;
    //objectContainer.BeginLifetimeScope();
}

#endregion

#region Properties

/// <summary>
/// Gets the resolved instance of a main window view model
/// </summary>
public MainWindowViewModel MainWindowViewModel
{
    get
    {
        return objectContainer.Resolve<MainWindowViewModel>();
    }
}

public FirstViewModel MyFirstViewModel 
{
    get
    {
        return objectContainer.Resolve<FirstViewModel>();
    }
}

public SecondViewModel MySecondViewModel 
{
    get
    {
        return objectContainer.Resolve<SecondViewModel>();
    }
}

5
单元测试应该针对 ViewModel类(业务逻辑),而不是View。如果在您的ViewModel类中初始化一个View,则设计上肯定存在严重问题。 - Rohit Vats
是的,但这个视图模型更像是一个容器视图模型,它动态地创建/设置视图(IView),并在XAML中使用它们在内容控件中。 - TMan
我喜欢在视图模型中设置我的视图(如果适用),因为这是我可以接近单元测试实际视图的最接近的方法。现在我知道你要说什么:“为什么我要尝试测试我的视图?”测试覆盖率越高,应用程序的质量就越好。就是这样。 - TMan
4
这完全是基于个人意见的。如果你喜欢那种方式,那就随你去吧。我不会对此发表评论。圣诞快乐! - Rohit Vats
我已更新以展示我的视图模型定位器代码。 - TMan
显示剩余3条评论
1个回答

1
这可能有点晚了,但也许还有用。不要在构造函数中解析objectContainer,而是通过属性来解析它:
//note this is a lazy getter, i.e. will be resolved when needed on the first call
private IContainer ObjectContainer
{
   get
   {
       if(objectContainer == null)
           objectContainer = App.ObjectContainer;
       return objectContainer:
   }
}

然后通过您的代码使用属性,而不是字段。另外,当我担心其他人使用我想要通过属性使用来强制执行的字段时,我会将其重命名为在 IntelliSence 中不容易被识别的名称(例如 zREgdnlksfObjectContainer :))请注意,该属性是私有的,因此没有真正的变化。您可以将属性设置为 internal,并将您的库标记为对单元测试可见,以便在单元测试中可以 Mock 它以 WhenCalled() 返回/解析 IContainer。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接