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



我刚刚看完Jason Dolinger在MVVM上的视频,我想澄清一下如何正确设置和单元测试我的视图模型的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()方法。

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

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

我们只需要对公共内容进行统一测试。

ps:不要错过我对你的问题的评论,在你的视图模型中直接使用IMessageBoxService而不是MessageBox。

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

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

  1. 尝试使用中继命令,而不是将VM传递到命令,尽量减少循环引用始终是最佳实践
  2. 切勿将不可测试对象引用到VM中(视图-包括消息框、具有复杂依赖树的大型对象等)

最新更新