C# 模拟抽象保护方法

C# 模拟抽象保护方法,c#,unit-testing,moq,C#,Unit Testing,Moq,我有一个抽象类: public abstract class MyClass { protected abstract bool IsSavable(); protected bool IsExecutable() { //New mode or edit mode if (ViewMode == ViewMode.New || ViewMode == ViewMode.Edit) { return

我有一个抽象类:

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在我的抽象类中由具体方法(IsExecutable)调用。我想测试一下这个方法。我知道你们中的大多数人都会建议在实现了“IsSavable”的类中测试这两种方法。不幸的是,这将有很多类,我只想测试我的方法一次

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

不,那是不合理的。您只需创建一个子类即可完成所需操作:

// Within your test code
class MyClassForTest : MyClass
{
    // TODO: Consider making this a property 
    protected override bool IsSavable()
    {
        return true;
    }
}
// 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());
然后,当您想要运行测试时,创建一个
MyClassForTest
的实例,而不仅仅是
MyClass


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

最快的方法是从“MyClass”继承并重写IsSavable

在测试中,区分正在测试的内容可能有点困难,但它确实做到了这一点


此外,您可以考虑一下设计-可能应该有两个类->一个用于可保存的行为,另一个用于不可保存的行为?

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

但是,通过推出重炮式扩展,并再次使用直接反射来实际调用SUT
IsExecutable
,实际上可以实现您想要的:

// Within your test code
class MyClassForTest : MyClass
{
    // TODO: Consider making this a property 
    protected override bool IsSavable()
    {
        return true;
    }
}
// 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());
//排列
var mockMyClass=new Mock();
mockMyClass.Object.ViewMode=ViewMode.New;//我在这里做了一两个假设。。。
mockMyClass.Protected().Setup(“IsSavable”).Returns(true);
//表演!
var result=(bool)mockMyClass.Object.GetType().InvokeMember(“IsExecutable”,
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
无效的
mockMyClass.Object,
无效);
//断言
断言(结果);
mockMyClass.Protected().Verify(“IsSavable”,Times.Once());

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

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