C# 如何使ViewModel中的InteractionRequest可测试?

C# 如何使ViewModel中的InteractionRequest可测试?,c#,wpf,unit-testing,moq,C#,Wpf,Unit Testing,Moq,我正在.NET4.0上为WPF使用PRISM和autofac,我想开发一个可测试的ViewModels。对于测试,我们使用nUnit和moq进行模拟 所以我有一门课: public class BackupViewModel : InteractionRequestNotificationObject { private readonly DelegateCommand backupCommand; private readonly IBackupCommandSe

我正在.NET4.0上为WPF使用PRISM和autofac,我想开发一个可测试的ViewModels。对于测试,我们使用nUnit和moq进行模拟

所以我有一门课:

public class BackupViewModel : InteractionRequestNotificationObject
   {
      private readonly DelegateCommand backupCommand;
      private readonly IBackupCommandService commandService;
      private readonly InteractionRequest<SaveBrowserDialogViewModel> saveDialogRequest = new InteractionRequest<SaveBrowserDialogViewModel>();

      public BackupViewModel(IBackupCommandService commandService, ISaveBrowserDialogViewModel saveBrowserDialog)
      {
          if(commandService == null)
              throw new ArgumentNullException("commandService"); 
          if(saveBrowserDialog == null)
              throw new ArgumentNullException("saveBrowserDialog");

          this.commandService = commandService;
          this.saveBrowserDialog = saveBrowserDialog;
          this.backupCommand = new DelegateCommand(Backup);
      }

      private void Backup()
      {
          saveBrowserDialog.Filters = "Zip archive (*.zip)|*.zip";
          saveDialogRequest.Raise((SaveBrowserDialogViewModel)saveBrowserDialog);
          if (saveBrowserDialog.Confirmed)
          {
              commandService.BackupDatabase(saveBrowserDialog.Path);
          }
      }
   }
公共类BackupViewModel:InteractionRequestNotificationObject
{
专用只读DelegateCommand backupCommand;
专用只读IBackupCommandService命令服务;
private readonly InteractionRequest saveDialogRequest=新建InteractionRequest();
公共备份视图模型(IBackupCommandService commandService,ISaveBrowserDialogViewModel saveBrowserDialog)
{
if(commandService==null)
抛出新的ArgumentNullException(“commandService”);
如果(saveBrowserDialog==null)
抛出新ArgumentNullException(“saveBrowserDialog”);
this.commandService=commandService;
this.saveBrowserDialog=saveBrowserDialog;
this.backupCommand=新的DelegateCommand(备份);
}
私有无效备份()
{
saveBrowserDialog.Filters=“Zip存档(*.Zip)|*.Zip”;
saveDialogRequest.Raise((SaveBrowserDialogViewModel)saveBrowserDialog);
如果(saveBrowserDialog.confirm)
{
backUpdatebase(saveBrowserDialog.Path);
}
}
}
我编写了单元测试:

[TestFixture]
public class BackupViewModelTests
{
    private BackupViewModel sut;
    private Mock<IBackupCommandService> backupCommandServiceMock;
    private Mock<ISaveBrowserDialogViewModel> saveDialogMock;

    [SetUp]
    public void Setup()
    {
        backupCommandServiceMock = new Mock<IBackupCommandService>();
        saveDialogMock = new Mock<ISaveBrowserDialogViewModel>();
        sut = new BackupViewModel(backupCommandServiceMock.Object, saveDialogMock.Object);
    }

    [Test]
    public void BackupViewModelShouldCallBackupFromCommandService()
    {
        saveDialogMock.Setup(x => x.Confirmed).Returns(true);
        sut.BackupCommand.Execute(null);
        backupCommandServiceMock.Verify(x => x.BackupDatabase(It.IsAny<string>()),Times.Once());
    }
}
[TestFixture]
公共类BackupViewModelTests
{
私有备份视图模型sut;
私有模拟备份CommandServiceMock;
私有Mock-saveDialogMock;
[设置]
公共作废设置()
{
backupCommandServiceMock=new Mock();
saveDialogMock=new Mock();
sut=新的BackupViewModel(backupCommandServiceMock.Object、saveDialogMock.Object);
}
[测试]
public void backupviewmodels应调用backupfromcandservice()
{
saveDialogMock.Setup(x=>x.confirm)。返回(true);
sut.BackupCommand.Execute(null);
backupCommandServiceMock.Verify(x=>x.backUpdatebase(It.IsAny()),Times.Once());
}
}

现在我还不知道如何模拟saveDialogRequest。提高(..)以便它可以处理模拟对象,而不是真正的SaveBrowserDialogViewModel。

最简单的答案是在静态类InteractionRequest的周围插入一个'seem'(请参见Michael Feathers的《有效处理遗留代码》)

这意味着将其推到接口(和实现)后面,然后向AutoFac注册此接口和实现,然后将实例作为构造函数参数传递给ViewModel类。这将允许您在测试中模拟接口

大概是这样的:

public interface IInteractionRequestWrapper<T>
{
    void Request(T instance);
}

public class InteractionRequestWrapper<T> : IInteractionRequestWrapper<T>
{
    private InteractionRequest<T> _saveDialogRequest;

    public InteractionRequestWrapper()
    {
        _saveDialogRequest = new InteractionRequest<T>();
    }
    public void Request(T instance)
    {
        _saveDialogRequest.Request(instance);
    }
}
公共接口IInteractionRequestWrapper
{
无效请求(T实例);
}
公共类InteractionRequestWrapper:IInteractionRequestWrapper
{
私有交互请求_saveDialogRequest;
公共交互请求包装器()
{
_saveDialogRequest=新的InteractionRequest();
}
公共无效请求(T实例)
{
_saveDialogRequest.Request(实例);
}
}