.net 我应该在视图模型上对方法或命令进行单元测试吗?

.net 我应该在视图模型上对方法或命令进行单元测试吗?,.net,wpf,mvvm,viewmodel,view-model-pattern,.net,Wpf,Mvvm,Viewmodel,View Model Pattern,我刚刚看完,我想澄清一下如何正确设置和单元测试视图模型的ICommand属性 考虑以下具有FooBarCommand ICommandProperty的ViewModel类 public class ViewModel : IViewModel { public ICommand FooBarCommand { get; private set; } public bool CanExectuteFooBar() { return true; }

我刚刚看完,我想澄清一下如何正确设置和单元测试视图模型的ICommand属性

考虑以下具有FooBarCommand ICommandProperty的ViewModel类

public class ViewModel : IViewModel
{
    public ICommand FooBarCommand { get; private set; }

    public bool CanExectuteFooBar()
    {
        return true;
    }

    public void FooBar()
    {
        //Do some FooBarish stuff
    }
}

public interface IViewModel
{
    void FooBar();
    System.Windows.Input.ICommand FooBarCommand { get; }
}

public class FooBarCommand : ICommand
{
    private ViewModel vm;

    public FooBarCommand(ViewModel vm)
    {
        this.vm = vm;
    }
    public bool CanExecute(object parameter)
    {
        return vm.CanExectuteFooBar();
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        vm.FooBar();
    }
}
因此,如果我在对ViewModel的FooBar功能进行单元测试,我可以通过调用testVM.FooBar()或通过调用testVM.FooBarCommand.Execute()执行命令来运行FooBar()。哪个是首选?我倾向于测试FooBarCommand属性,因为视图上的按钮最终被绑定到FooBarCommand属性,而不是FooBar()方法


此外,由于我的视图将绑定到IViewModel而不是ViewModel,因此我应该能够完全正确地从IViewModel接口中省略FooBar()方法?

为什么不使用DelegateCommand或RelayCommand?如果你想这样做,你就不必问这个问题,因为只有Comand本身是公共的——那么canexecute和execute方法是私有的

我们只需要对公共物品进行联合测试


ps:请不要错过我对您问题的评论,在viewmodels中直接使用IMessageBoxService而不是MessageBox。

在某些情况下,测试命令可能是另一个测试夹具,因为命令后面有逻辑(启用禁用按钮)。如果您仅在
CanExecute
方法上返回true,那么对命令进行单元测试是没有用的,但是当禁用启用按钮包含复杂的逻辑时,您应该在不同的装置中测试它

注意(如果不同意,则忽略):

  • 尝试使用其中一个,然后将VM传递到 命令,最小化循环引用始终是最佳实践
  • 切勿将不可测试对象引用到VM中(视图-包括messagebox、具有复杂依赖关系树的大型对象等)

  • 如果要对viewmodel进行单元测试,则应使用IMessageboxService替换System.Windows.MessageBox.Show,否则会遇到麻烦;)哦,是的,我知道当我做这个例子的时候,我并没有想到这一点。我现在在问题中解决了这个问题。关于从接口中删除FooBar方法,您是对的。方法和CanExecute方法实际上可以是内部的。如果您开始测试方法和命令,这与测试类的私有实现和公共“接口”没有什么不同,因为视图模型的使用者只使用命令。