简体   繁体   English

模拟抽象保护方法

[英]Mock abstract protected method

I have an abstract class: 我有一个抽象类:

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;
    }
}

I would like to unit test this class. 我想对这门课进行单元测试。 Therefor I need to mock the "IsSavable" method. 因此,我需要模拟“IsSavable”方法。 It should always return "true". 它应该总是返回“true”。

I know how to mock my abstract class with Moq. 我知道如何用Moq模拟我的抽象类。 But how can I mock my abstract protected method so it returns true? 但是,如何模拟我的抽象受保护方法,使其返回true?

The function IsSavable is called in my abstract class by a concrete method (IsExecuteable). 函数IsSavable在我的抽象类中通过具体方法(IsExecuteable)调用。 I would like to test this method. 我想测试一下这个方法。 I know that most of you will recommend to test both in the class where "IsSavable" is implemented. 我知道大多数人会建议在实现“IsSavable”的类中测试它们。 Unfortunately this will be a lot of classes and I would like to test my method IsExecutable only once. 不幸的是,这将是很多类,我想测试我的方法IsExecutable只有一次。

I would like to unit test this class. 我想对这门课进行单元测试。 Therefor I need to mock the "IsSavable" method. 因此,我需要模拟“IsSavable”方法。 It should always return "true". 它应该总是返回“true”。

No, that's a non-sequitur. 不,这是一个不成功的人。 You can just create a subclass which does what you want: 你可以创建一个你想要的子类:

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

Then when you want to run a test, create an instance of MyClassForTest instead of just MyClass . 然后,当您想要运行测试时,创建一个MyClassForTest实例,而不仅仅是MyClass

Personally I prefer to use mocking frameworks for dependencies rather than the classes I'm testing. 就个人而言,我更喜欢使用模拟框架来实现依赖,而不是我正在测试的类。

Just to corroborate what @Jon says - the fact that you are trying to Mock a protected method AND invoke another protected method on an abstract class is indicative of a smell. 只是为了证实@Jon所说的 - 你试图模拟受保护的方法并在抽象类上调用另一个受保护的方法这一事实表明了一种气味。

But, by bringing out the heavy artillery - Moq's Protected() extensions, and again using direct reflection, to actually Invoke the SUT IsExecutable , it is actually possible to do what you want: 但是,通过引出重炮--Moq的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());

But I personally would tend to rethink the design and method couplings at this point. 但我个人倾向于重新考虑此时的设计和方法耦合。

The quickest thing to do it to inherit from "MyClass" and override the IsSavable. 从“MyClass”继承并覆盖IsSavable是最快的事情。

It might be bit harder in the test to differentiate what is being tested but it does the trick. 在测试中可能有点难以区分正在测试的内容,但它可以解决问题。

Furthermore you could think about the design - maybe there should be two classes -> one for Saveable behaviour and one for unSavable? 此外,您可以考虑设计 - 也许应该有两个类 - >一个用于Saveable行为,一个用于unSavable?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM