简体   繁体   English

不调用受模拟的抽象类的受保护的虚方法

[英]Protected virtual method of a mocked abstract class is not called

I am mocking an abstract class with NSubstitute and expect its protected virtual method to be called. 我正在使用NSubstitute模拟一个抽象类,并期望调用其受保护的虚方法。

public abstract class A 
{
    protected virtual bool ProtectedMethod()
    {
        return true;
    }
    public bool PublicMethod()
    {
        return ProtectedMethod();
    }
}

public class ATest
{
    [Fact]
    public void Test()
    {
        var anA = Substitute.For<A>();

        var result = anA.PublicMethod();

        Assert.True(result);
    }
}

This test fails when executed. 执行时此测试失败。 In fact, it fails even if the class is not abstract. 事实上,即使课程不是抽象的,它也会失败。 If this is normal behavior, what should I do to ensure the ProtectedMethod is called? 如果这是正常行为,我该怎么做才能确保调用ProtectedMethod?

PS. PS。 If the method is not virtual, it works as expected. 如果该方法不是虚拟的,则按预期工作。

As pointed out in the comments, be careful substituting for classes . 正如评论中指出的那样, 小心取代课程 I recommend installing the NSubstitute.Analyzers to pick up issues with class substitutes at compile time. 我建议安装NSubstitute.Analyzers来在编译时获取类替换的问题。

The reason this test is failing is because you are substituting for A , so NSubstitute replaces all virtual implementations with substitute ones (which generally return default unless otherwise stubbed out, in this case false ). 此测试失败的原因是因为您要替换A ,因此NSubstitute用替换的替换所有虚拟实现 (除非另有说明,否则通常返回default ,在这种情况下为false )。

You can use a partial substitute which will maintain the existing implementation by default (ie ProtectedMethod will keep returning true as per the base implementation): 您可以使用部分替换 ,它将默认维护现有实现(即ProtectedMethod将根据基本实现继续返回true ):

[Fact]
public void TestUsingPartialSub() {
    var anA = Substitute.ForPartsOf<A>();

    var result = anA.PublicMethod();

    Assert.True(result);
}

"... what should I do to ensure the ProtectedMethod is called?" “......我该怎么做才能确保调用ProtectedMethod?”

NSubstitute can not assert on protected methods (it works via the publicly accessible API). NSubstitute无法对受保护的方法断言(它通过可公开访问的API工作)。 If possible, you can refactor the code to use a strategy pattern to inject the protected behaviour. 如果可能,您可以重构代码以使用策略模式来注入受保护的行为。 This will make the code more flexible (including the flexibility to inject different behaviour for testing), at the cost of a slightly more complex design. 这将使代码更加灵活(包括为测试注入不同行为的灵活性),代价是稍微复杂的设计。

public interface IProtectedMethod {
    bool ProtectedMethod();
}

public class AA {
    private readonly IProtectedMethod x;
    public AA(IProtectedMethod x) {
        this.x = x;
    }
    public bool PublicMethod() {
        return x.ProtectedMethod();
    }
}

public class AATest {
    [Fact]
    public void TestUsingStrategySub() {
        var x = Substitute.For<IProtectedMethod>();
        var anA = new AA(x);

        anA.PublicMethod();

        x.Received().ProtectedMethod();                
    }
}

(Please excuse the naming in this example, I've tried to keep it similar to the original to make it clearer where the various bits of logic have moved.) (请原谅这个例子中的命名,我试图让它与原版保持相似,以便在各种逻辑位移动的地方更清楚。)

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

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