【问题标题】:Unit testing with Mock when viewmodel contains an ICommand当 viewmodel 包含 ICommand 时使用 Mock 进行单元测试
【发布时间】:2013-08-12 16:26:24
【问题描述】:

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

问题是我遇到了一个场景,由于我的一个名为 ApplyChangesCommand 的命令中存在依赖关系,我需要模拟视图模型。我不相信依赖是一件坏事。在这一点上是比较必要的。

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

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

简单的例子是:

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

Mock 有什么方法可以让我真正调用 ApplyChangesCommand 的 _somethingToExecute? Callbase 没有削减它,我想不出任何其他方法来做到这一点。

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

任何建议表示赞赏。

谢谢

【问题讨论】:

  • 我不得不读了几遍才能理解你的要求,所以我可能会离开这里。您在对命令或包含命令的视图模型进行单元测试时遇到问题吗?如果是命令(这就是我认为您要问的),您难道不能将传入的委托模拟到 MyCustomCommand 构造函数,然后验证模拟委托是否被调用?那将是该命令的正确单元测试。测试 ViewModel 将是类似的 - 模拟命令并让其 Execute 调用调用 _somethingToExecute
  • 非常感谢您的建议。让我看看……听起来它可能是在正确的轨道上!我的问题实际上围绕着对命令进行单元测试,因为我在模拟视图模型。由于视图模型是模拟的,因此命令本身为空

标签: c# unit-testing mocking viewmodel icommand


【解决方案1】:

好的,既然我有更多的时间来看看这不是在工作中匆忙,我明白了这个问题。你应该做的是使用注入的工厂来创建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 的命令进行单元测试的全部内容。如果您想测试行为是否符合您的预期(也就是说,它执行传入的委托并使用该委托返回预期值),那么这就是验收测试的领域。

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

就个人而言,我不会将这样的代表传递给Command。相反,我会注入 Command 需要的任何东西,并将所有逻辑都放在 Command 中,在那里更容易进行单元测试,并且对 VM 的依赖更松散。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-16
    相关资源
    最近更新 更多