Защищенный виртуальный метод макета абстрактного класса не вызывается - PullRequest
0 голосов
/ 16 мая 2019

Я издеваюсь над абстрактным классом с помощью 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 голосов
/ 16 мая 2019

Как указано в комментариях, будьте осторожны при замене классов .Я рекомендую установить NSubstitute.Analyzers для выявления проблем с заменителями классов во время компиляции.

Причина, по которой этот тест не пройден, заключается в том, что вы заменяете A, поэтому NSubstitute заменяет все виртуальные реализации заменяющими (которые обычно возвращают default, если не исключено иное, в данном случае false).

Вы можете использовать частичный заменитель , которыйбудет поддерживать существующую реализацию по умолчанию (т.е. ProtectedMethod будет продолжать возвращать true в соответствии с базовой реализацией):

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

    var result = anA.PublicMethod();

    Assert.True(result);
}

"... что я должен сделать, чтобы убедиться, что ProtectedMethodnamed? "

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

(Пожалуйста, извините за наименование в этом примере, япытался сделать его похожим на оригинал, чтобы было яснее, куда переместились различные кусочки логики.)

...