Использование Moq для установки индексаторов в С#

Мне трудно понять, как установить indexers в С# с помощью Moq. Документация Moq слаба, и я много раз искал... то, что я хотел бы сделать, аналогично в решении Как Moq Установка свойства Indexed:

var someClass = new Mock<ISomeClass>();
someClass.SetupSet(o => o.SomeIndexedProperty[3] = 25);

Я хочу изменить выше, чтобы работать для любого индекса и любого значения, поэтому я могу просто сделать что-то вроде этого:

someClass.Object.SomeIndexedProperty[1] = 5;

В настоящее время у меня есть следующее, которое отлично работает для индексатора с индексированным свойством, но если я когда-либо установил значение Moq, он игнорирует его:

var someValues = new int[] { 10, 20, 30, 40 };
var someClass = new Mock<ISomeClass>();
someClass.Setup(o => o.SomeIndexedProperty[It.IsAny<int>()])
    .Returns<int>(index => someValues[index]);

// Moq doesn't set the value below, so the Assert fails!
someClass.Object.SomeIndexedProperty[3] = 25;
Assert.AreEqual(25, someClass.Object.SomeIndexedProperty[3]);

Ответ 1

Я нашел решение своей проблемы. Это требует сдвига в моем мышлении... Я искал использовать NUnit Assert, чтобы проверить, что установщик индексатора в моем макете someClass вызывался с правильным значением.

Кажется, что с помощью Moq поддерживаемый способ сделать это - использовать функцию VerifySet. Надуманный пример:

someClass.Object.SomeIndexedProperty[3] = 25;
someClass.VerifySet(mock => mock.SomeIndexedProperty[3] = 25);

Пропуск unit test, так как SomeIndexedProperty[3] установлен в 25, но в противном случае не будет.

Ответ 2

Использование Moq 3.1.416.3

Настройка не будет работать для индексировщиков (потому что она принимает выражение, которое означает, что присваивание присваивания исключено)

поэтому вам нужно использовать SetupSet, например

_settingsStore.SetupSet(store => store["MruNotes"] = It.IsAny<string>())
                .Callback<string,string>( (key, value) => persistedValue = value);

Небольшое предостережение: это выражение совпадает только с ключом "MruNotes". Я не смог использовать такой помощник, как It.IsAny для ключа.

Ответ 3

В вашем тесте ваши единственные установленные ожидания для getter индексатора - и это всегда будет возвращать соответствующее значение из вашего массива. Индексатор не ведет себя как настоящая вещь. Вы можете попробовать несколько вещей, чтобы исправить это:

  • Вы можете проверить, не заблокирован ли этот индекс. Я лично использую RhinoMocks, поэтому я понятия не имею, реализовано ли это

    someClass.SetupProperty(f => f.SomeIndexedProperty);
    
  • Вы также можете попытаться издеваться над установщиком и заставить его изменить базовый массив. Мое первое предположение заключалось в том, чтобы попробовать что-то в этом направлении (без гарантии, что он будет работать):

    someClass.Setup(o => o.SomeIndexedProperty[It.IsAny<int>()] = It.IsAny<int>())
    .Callback((index, value) => someValues[index] = value);
    
  • Или, если интерфейс ISomeClass достаточно мал, вы могли бы просто создать реализацию-заглушку самостоятельно (что бы реализовать индексатор как словарь, массив и т.д.)