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

时间:2019-05-15 23:15:10

标签: c# unit-testing nsubstitute

我正在用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);
    }
}

该测试在执行时失败。实际上,即使类不是抽象的,它也会失败。如果这是正常行为,该怎么办才能确保调用ProtectedMethod?

PS。如果该方法不是虚拟的,则它将按预期工作。

1 个答案:

答案 0 :(得分:0)

正如评论中所指出的,be careful substituting for classes。我建议安装NSubstitute.Analyzers以在编译时解决类替换的问题。

此测试失败的原因是因为您要替换A,所以要替换NSubstitute replaces all virtual implementations with substitute ones(通常返回default,除非另有说明,在这种情况下为false

您可以使用partial substitute,它会默认保留现有的实现(即ProtectedMethod将根据基本实现不断返回true):

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

    var result = anA.PublicMethod();

    Assert.True(result);
}
  

“ ...应该怎么做才能确保调用ProtectedMethod?”

NSubstitute无法断言受保护的方法(它通过可公开访问的API起作用)。如果可能,您可以重构代码以使用策略模式注入受保护的行为。这将使代码更灵活(包括为测试注入不同行为的灵活性),但设计会稍微复杂一些。

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

(在本示例中,请原意命名,我试图使其与原始名称保持相似,以使逻辑的各个部分移到更清楚的位置。)