Moq не вызывает правильный метод в дереве наследования - PullRequest
1 голос
/ 18 октября 2019

У меня есть исходный код фреймворка, который я не хочу изменять. Однако мне нужно изменить его поведение. Я достигаю этого, создавая классы расширения для кода фреймворка и изменяя поведение по своему усмотрению. Имея это в виду, вы сможете лучше понять, чего я пытаюсь достичь.

Код фреймворка:

public interface IItem
{
    void PerformAction();
}

public class Item : IItem
{
    public IItemChild itemChild;

    public Item(IItemChild ic)
    {
        itemChild = ic;
    }

    public void PerformAction()
    {
        itemChild.PerformAction(1, c:1);
    }
}

public interface IItemChild
{
    void PerformAction(int a = 0, int b = 0, int c = 0);
}

public class ItemChild : IItemChild
{
    public virtual void PerformAction(int a = 0, int b = 0, int c = 0)
    {

    }
}

Код расширения фреймворка:

public interface IItemExtension : IItem
{

}

public class ItemExtension : Item, IItemExtension
{
    public ItemExtension(IItemChildExtension ice) : base(ice) { }
}

public interface IItemChildExtension : IItemChild
{
    void PerformAction(int a = 0, int b = 0, int c = 0);
}

public class ItemChildExtension : ItemChild, IItemChildExtension
{
    public void PerformAction(int a = 0, int b = 0, int c = 0)
    {

    }
}

I 'Мы также написали тестовый класс для проверки поведения кода расширения:

public class Tests
{
    [SetUp]
    public void Setup()
    {
    }

    [Test]
    public void Test1()
    {
        var itemChildMock = new Mock<IItemChildExtension>();
        itemChildMock.Setup(mock => mock.PerformAction(1, 0, 1)).Callback(() =>
        {
            var test = 2;
        });

        var itemExtension = new ItemExtension(itemChildMock.Object);
        //itemExtension = new ItemExtension(new ItemChildExtension());
        itemExtension.PerformAction();

        var invocations = itemChildMock.Invocations;

    }
}

Функция обратного вызова в этом коде не запускается. После проверки ложных вызовов я заметил, что IItemChild.PerformAction (1, 0, 1) был вызван, хотя для IItemChildExtension был создан макет.

Раскомментирование второго назначения itemExtension избавляет от макета и использует «реальный»"реализация вместо. Выполнение этого приводит к вызову IItemChildExtension.PerformAction (1, 0, 1). Я хотел бы, чтобы мой тест выполнял тот же метод, который выполнялся бы без макетов.

Почему mock вызывает неправильный метод? Я пропустил какую-то конфигурацию, которая привела бы к желаемому поведению?

1 Ответ

2 голосов
/ 18 октября 2019

IItemChildExtension.PerformAction скрывает унаследованный элемент от IItemChild

И показанная настройка была сделана для IItemChildExtension.PerformAction, а не IItemChild

Вам нужно будет явно указать Moq, какого члена вы ожидаетебыть вызванным.

//Arrange
var itemChildMock = new Mock<IItemChildExtension>();
itemChildMock.As<IItemChild>().Setup(mock => mock.PerformAction(1, 0, 1)).Callback(() => {
    var test = 2;
});

var itemExtension = new ItemExtension(itemChildMock.Object);
//itemExtension = new ItemExtension(new ItemChildExtension());

//Act
itemExtension.PerformAction();

var invocations = itemChildMock.Invocations;

Обратите внимание на использование .As<IItemChild>() при настройке ожидания.

С учетом вышеизложенного измените тестовые упражнения, как ожидается.

Если яудалить элемент, который скрывал производный элемент

public interface IItemChildExtension : IItemChild {
    //void PerformAction(int a = 0, int b = 0, int c = 0);
}

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

...