Я хотел бы написать модульный тест, который переопределяет некоторое свойство только для чтения, которое находится довольно глубоко в графе объектов.Я имею в виду такой метод:
public string MethodToTest(IClassA classA)
{
return classA.ClassB.ClassC.ClassD.Items[0].Name;
}
Где каждый ClassN реализует интерфейс IClassN, а каждое свойство доступно только для чтения.Таким образом, пример интерфейса будет:
IClassA
public interface IClassA { IClassB ClassB { get; } }
И реализация будет выглядеть так:
ClassA
public class ClassA : IClassA
{
public ClassA() { ClassB = new ClassB(); }
public IClassB ClassB { get; }
}
Я хочу переопределить значение, возвращаемое classA.ClassB.ClassC.ClassD.Items [0] .Name , с минимальными усилиями, насколько это возможно.Я мог бы создать Mock и иметь .Setup для возврата IClassB и пройти всю цепочку, используя только Moq.Но я бы хотел этого избежать, если это возможно.
Я пробовал много разных вещей, но безуспешно.
Попытка # 1
Я думал, что смогу создать цепочку, используя fixture.Build()
var moqItem = new Mock<IItem>();
moqItem.Setup(item => item.Name).Returns("My expected value");
var fakeClassD = fixture.Build<IClassD>()
.With(d => d.Items, new[] { moqItem.Object });
Очевидно, я оставил некоторые слои,но это не важно.Это терпит неудачу, потому что свойства доступны только для чтения.
Попытка # 2
Затем я подумал, что мог бы «заморозить» конкретный экземпляр, и всякий раз, когда прибор создавал объект,если бы он увидел что-то подобное, он бы использовал это.Я думал, что следую приведенному здесь примеру: https://blog.ploeh.dk/2010/03/17/AutoFixtureFreeze/
Это показывает примерно такой код: var expectedName = fixture.Freeze("Name");
Исходя из этого, я пытался сделать что-то вроде этого:
var moqItem = new Mock<IItem>();
moqItem.Setup(x => x.Name).Returns("My expected value");
fixture.Freeze<IItem[]>(new IItem[] { moqItem.Object });
К сожалению, это даже не скомпилируется.Метод Freeze ожидает Func некоторого класса Composer типа IItem [], и я не смог выяснить, как это сделать.Если я удаляю тип, аналогично примеру кода, я получаю
fixture.Freeze(new IItem[] { moqItem.Object });
, который также не удается скомпилировать.
Попытка # 3
var moqItem = new Mock<IItem>();
moqItem.Setup(x => x.Name).Returns("My expected value");
fixture.Inject<IItem[]>(new IItem[] { moqItem.Object });
Очень похоже на попытку # 2 - компилируется только это.Я думал, что всякий раз, когда устройству нужен массив IItem [], он будет использовать тот, который я настроил.Но когда я звоню
var attempt3 = fixture.Create<IClassA>();
Поведение не то, на что я надеялся.try3.ClassB.ClassC.ClassD.Items не содержит моего макета.
TL; DR - Как я могу переопределить значение, возвращенное из Item[0].Name
, с наименьшим количеством кода / усилий?