c# - 当 viewmodel 包含 ICommand 时使用 Mock 进行单元测试

标签 c# unit-testing mocking viewmodel icommand

我有一个类(为简单起见,我将其称为 MyCustomCommand),它基本上接受两个用于 Execute 和 CanExecute 的委托(delegate)。此类实现 ICommand。然后,这允许我在我的 View 模型中声明一个属性,我从 XAML 绑定(bind)到该属性。

问题是我遇到了一个场景,由于依赖于我的一个名为 ApplyChangesCommand 的命令,我需要模拟 View 模型。我不相信依赖性是一件坏事。这个时候比较有必要。

由于这种依赖性,我正在使用 Mock Setups 创建一个基本上“什么都不做”来规避依赖性的回调。

既然我已经模拟了 View 模型,那么任何实例属性现在当然都是空的。这包括我的命令。

简单的例子是:

private void _somethingToExecute;
public ICommand ApplyChangesCommand { get { return MyCustomCommand(_somethingToExecute, e=>true); }

有什么方法可以让我实际调用 ApplyChangesCommand 的 _somethingToExecute? Callbase 无法解决问题,我也想不出任何其他方法来做到这一点。

一种解决方法是公开“_somethingToExecute”并在我的测试中创建 ApplyChangesCommand,但我不喜欢。

感谢任何建议。

谢谢

最佳答案

好吧,既然我有更多时间来研究这个不匆忙的工作,我明白了这个问题。您应该做的是使用注入(inject)工厂来创建 ApplyChangesCommand。然后,为了对您的 VM 进行单元测试,您只需验证该命令是否返回工厂创建的命令。下面是一个例子:

public class MyViewModel
{
    private MyCustomCommandFactory _commandFactory;
    private void _somethingToExecute;

    public MyViewModel(MyCustomCommandFactory commandFactory)
    {
        _commandFactory = commandFactory;
    }

    public ICommand ApplyChangesCommand  
    { 
        get 
        { 
            return _commandFactory.Create(_somethingToExecute, e=>true);
        }
    }
}

这假定您希望在每次调用 get 时创建一个新命令(这似乎是您设置它的方式)。如果您只想为 VM 的生命周期创建一个命令,显然您可以通过 VM 构造函数中的工厂创建命令。

要对此进行单元测试,您可以这样做:

[Test]
public void ApplyChangesCommand_Always_ReturnsFactoryCreatedCommand
{
    Mock<ICommand> mockCreatedCustomCommand = new Mock<ICommand>();
    Mock<MyCustomCommandFactory> mockCommandFactory = new Mock<MyCustomCommandFactory>();
    mockCreatedCustomCommand.Setup(p => p.Create(It.IsAny<Action>(), e => true))
                            .Returns(mockCreatedCustomCommand.Object);
    Assert.That(systemUnderTest.ApplyChangesCommand, Is.SameAs(mockCreatedCustomCommand.Object));
}

(将 Action 更改为您的代表实际上是什么)。

这就是您对 VM 命令进行单元测试所需要的全部内容。如果您想要测试行为是否符合您的预期(意思是,它执行传入的委托(delegate)并使用该委托(delegate)返回预期值),那么这就是验收测试的领域。

注意:我在测试示例中使用了 Moq 模拟框架语法。

就我个人而言,我不会将这样的委托(delegate)传递给 Command。相反,我会注入(inject) Command 需要的任何内容,并在 Command 中包含所有逻辑,在那里它更容易进行单元测试,并且对 VM 的依赖性更宽松。

关于c# - 当 viewmodel 包含 ICommand 时使用 Mock 进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18192027/

相关文章:

ios - 如何在不使用 OCMock 的情况下模拟局部变量

eclipse - 找不到模拟 assertEquals

c# - 如何在 ASP.NET Web API 中对自定义 JsonConverter 进行单元测试?

java - Mockito 和 HttpServletResponse - 将输出写入文本文件

c# - 这个正则表达式是什么意思

unit-testing - 如何使用 Carrierwave + FactoryGirl 测试上传

按属性索引的 C# 集合?

typescript - 在每个 Jest 测试中模拟不同的 TypeScript 常量

c# - FluentFTP:根据验证程序,远程证书无效

c# - 服务层和存储库的职责