【问题标题】:Mock abstract protected method模拟抽象受保护方法
【发布时间】:2014-11-27 15:19:13
【问题描述】:

我有一个抽象类:

public abstract class MyClass
{
    protected abstract bool IsSavable();

    protected bool IsExecutable()
    {
        //New mode or edit mode
        if (ViewMode == ViewMode.New || ViewMode == ViewMode.Edit)
        {
            return IsSavable();
        }

        //Search mode
        if (ViewMode == ViewMode.Search)
        {
            return true;
        }

        return false;
    }
}

我想对这个类进行单元测试。因此,我需要模拟“IsSavable”方法。它应该总是返回“true”。

我知道如何用 Moq 模拟我的抽象类。但是如何模拟我的抽象受保护方法使其返回 true?

函数 IsSavable 在我的抽象类中由具体方法 (IsExecuteable) 调用。我想测试这个方法。我知道你们中的大多数人会建议在实现“IsSavable”的类中进行测试。不幸的是,这将是很多类,我只想测试我的方法 IsExecutable 一次。

【问题讨论】:

  • 可能你不知道。我更喜欢只测试公共方法。
  • 测试抽象方法的意义何在?没有实现。
  • @Vadim @Michael 为什么你们认为这是关于测试IsSavable 方法?如果 OP 需要测试 MyClass 的任何实例成员,他将需要从 MyClass 派生的 some 类的实例。 Something 必须提供IsSavable 的实现。这可以是来自项目其他地方的真实的(在这种情况下,将不清楚正在测试哪个类),也可以是为了这个测试而创建的子类,这是我所提倡的。或者它可能是一个模拟,尽管我认为在这种情况下不需要这样做。
  • 我已经更新了问题。希望这能说明问题。

标签: c# unit-testing moq


【解决方案1】:

我想对这个类进行单元测试。因此,我需要模拟“IsSavable”方法。它应该总是返回“true”。

不,这是不合逻辑的。你可以创建一个子类来做你想做的事:

// Within your test code
class MyClassForTest : MyClass
{
    // TODO: Consider making this a property 
    protected override bool IsSavable()
    {
        return true;
    }
}

然后,当您要运行测试时,请创建 MyClassForTest 的实例,而不仅仅是 MyClass

我个人更喜欢为依赖项使用模拟框架,而不是我正在测试的类。

【讨论】:

    【解决方案2】:

    只是为了证实@Jon 所说的 - 你试图模拟一个受保护的方法并在抽象类上调用另一个受保护的方法这一事实表明了一种气味。

    但是,通过推出重炮 - Moq's Protected() 扩展,并再次使用直接反射,实际调用 SUT IsExecutable,实际上可以做你想做的事:

    // Arrange
    var mockMyClass = new Mock<MyClass>();
    mockMyClass.Object.ViewMode = ViewMode.New; // I've made an assumption or two here ...
    mockMyClass.Protected().Setup<bool>("IsSavable").Returns(true);
    
    // Act!
    var result = (bool)mockMyClass.Object.GetType().InvokeMember("IsExecutable",
        BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
        null,
        mockMyClass.Object,
        null);
    
    // Assert
    Assert.IsTrue(result);
    mockMyClass.Protected().Verify<bool>("IsSavable", Times.Once());
    

    但我个人倾向于在这一点上重新考虑设计和方法的耦合。

    【讨论】:

      【解决方案3】:

      从“MyClass”继承并覆盖 IsSavable 的最快方法。

      在测试中区分正在测试的内容可能会有点困难,但它可以解决问题。

      此外,您还可以考虑设计 - 也许应该有两个类 -> 一个用于可保存行为,一个用于不可保存?

      【讨论】:

        猜你喜欢
        • 2012-01-08
        • 1970-01-01
        • 2015-08-02
        • 1970-01-01
        • 1970-01-01
        • 2017-06-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多