最小数量的模拟对象与实际类有多少相似?

时间:2018-12-03 11:36:24

标签: c# unit-testing mvvm moq

我是单元测试和模拟的新手。所以请不要烤我:)

我写了我的第一个非常简单的单元测试,它似乎可以工作。但是,我不知道发生了什么事。我要测试的是,在调用主窗口的OpenEditView()方法时,使用类型为EditViewModel的参数调用showDialog方法。我正在使用对话框服务来使我的代码满足MVVM设计模式。而且我正在使用工厂,而不是直接在要测试的方法中直接创建视图模型类的对象。工厂只是创建并返回要求的对象。

运行时,测试通过。

如果不设置ViewModelFactoryMock的CreateEditViewModel方法,怎么办?在测试期间调用该方法时,该方法究竟返回什么?或者从更广泛的意义上讲:模拟对象与实际对象多少相似?我什么时候需要设置模拟对象的方法?

vm.OpenEditView()

public void OpenEditView()
    {
        EditViewModel viewModel = viewModelFactory.CreateEditViewModel(Argument1, Argument2, ...);
        bool? result = dialogService.ShowDialog(viewModel);
    }

单元测试:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        // Arrange
        var DialogServiceMock = new Mock<IDialogService>();

        var ViewModelFactoryMock = new Mock<IViewModelFactory>();

        DialogServiceMock
            .Setup(x => x.ShowDialog(It.IsAny<EditViewModel>()))
            .Returns(true)
            .Verifiable();

        MainWindowViewModel vm = new MainWindowViewModel(DialogServiceMock.Object, ViewModelFactoryMock.Object);

        // Act
        vm.OpenEditView();

        // Assert
        DialogServiceMock.Verify(mock => mock.ShowDialog(It.IsAny<EditViewModel>()));
    }
}

IViewModelFactory

    public interface IViewModelFactory
{
    EditViewModel CreateEditViewModel(Argument1, Argument2, ...);
}

2 个答案:

答案 0 :(得分:0)

  

如果不设置ViewModelFactoryMock的CreateEditViewModel方法,怎么办?

对于模拟返回的结果,您实际上不做任何事情,因此,由于值为空,因此没有机会失败。

  

在测试过程中调用该方法时,究竟返回什么?

在这种情况下,viewModel的值为 null ,因为未在模拟中设置期望。

测试通过是因为验证

DialogServiceMock.Verify(mock => mock.ShowDialog(It.IsAny<EditViewModel>()));

期望It.IsAny<EditViewModel>()可以包含 null

如果您想验证实际实例,则可以创建一个实例并将模拟程序设置为符合预期的行为。假设EditViewModel不是sealed

[TestMethod]
public void TestMethod1()
{
    // Arrange
    var DialogServiceMock = new Mock<IDialogService>();

    var ViewModelFactoryMock = new Mock<IViewModelFactory>();

    var viewModel = Mock.Of<EditViewModel>(); // Or new EditViewModel(...);

    ViewModelFactoryMock
        .Setup(_ => _.CreateEditViewModel(It.IsAny<Argument1>(),....));
        .Returns(viewModel);

    DialogServiceMock
        .Setup(x => x.ShowDialog(It.IsAny<EditViewModel>()))
        .Returns(true)
        .Verifiable();

    MainWindowViewModel vm = new MainWindowViewModel(DialogServiceMock.Object, ViewModelFactoryMock.Object);

    // Act
    vm.OpenEditView();

    // Assert

    //verify that the mocked view model was actually used.
    DialogServiceMock.Verify(mock => mock.ShowDialog(viewModel));
}
  

模拟对象与实际对象多少相似?

它们(模拟)是从基本类型派生的,因此它们是实际对象/接口的实现

  

何时需要设置模拟对象的方法?

仅当需要他们的行为才能完成测试时。

答案 1 :(得分:0)

  

模拟对象有多少类似于实际对象?

没什么,而是一个模拟的设置。 MOQ是基于动态代理的模拟系统。因此,当您为接口(您要模拟其api的接口)创建一个模拟(存根)时,它将创建该接口的代理,从广义上讲,它将通过继承模拟和{{1 }}特定的方法(这就是为什么MOQ只可以使用overridevirtual方法的原因。

因此,当调用实际的api方法时,测试运行程序确保使用您传递的任何参数而不是实际参数来调用拦截器方法(Setup方法)。