Перемешивание интерфейса Fluent с использованием Moq - PullRequest
2 голосов
/ 28 апреля 2020

Я рассмотрел ряд вопросов по этой теме, но ни один из них, похоже, не решает мою проблему.

У меня есть код, который выглядит примерно так ...

IBaseDataCollector<MyClass> myDataCollector;

myDataCollector = new Mock<IBaseDataCollector<MyClass>>();

systemUnderTest = new Thing(myDataCollector.Object);

И в моем Thing классе ...

var collection = myDataCollector.SomeMethod()
                     .SomeSecondMethod()
                     .GetData();

, где оба SomeMethod() и SomeSecondMethod() возвращают this (ie экземпляр myDataCollector)

Когда я запускаю тест, я получаю NullReferenceException на том же месте, где я звоню myDataCollector.

Я попытался добавить это в настройках теста ...

myDataCollector.Setup(_=> _.SomeMethod()),Returns(myDataCollector.Object);

но это даже не скомпилируется, жалуясь на то, что «Не удалось разрешить метод Returns (IBaseDataCollector)» »

Теперь, если я реорганизую свой класс Thing для чтения ...

myDataCollector.SomeMethod();
myDataCollector.SomeSecondMethod()
var collection = myDataCollector.GetData();

мой тест выполняется правильно.

Если бы это было так, я бы просто реорганизовал свой код и продолжил жизнь, но на самом деле мне нужно вызывать мой код внутри SelectMany call ...

var collection = list.SelectMany(_=> myDataCollector.SomeMethod()
                     .SomeSecondMethod(_)
                     .GetData());

Опять же, я знаю, что я мог бы заменить SelectMany, скажем, ForEach и вручную заполнить коллекцию результатами каждой итерации вызов GetData() так что я могу избавиться от беглого элемента вызовов, но это означает рефакторинг кода только для того, чтобы тесты работали, что кажется неправильным.

Как мне вызывать Setup() для моих объектов Mocked, чтобы сделать мои беглые звонки работают?

1 Ответ

2 голосов
/ 28 апреля 2020

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

    public class UnitTestExample
    {

        [Fact]
        public void UnitTestExample1()
        {
            var myClassInterfaceMock = new Mock<IInterface<MyClass>>();
            var instance = myClassInterfaceMock.Object;
            var myList = new List<MyClass>()
            {
                new MyClass() { Attribute = 1 }
            };

            myClassInterfaceMock.Setup(_ => _.SomeMethod()).Returns(instance);
            myClassInterfaceMock.Setup(_ => _.SomeSecondMethod()).Returns(instance);
            myClassInterfaceMock.Setup(_ => _.GetData()).Returns(myList);

            var myDependentClass = new MyDependentClass(instance);
            var result = myDependentClass.DoTheThing();

            Assert.True(result.Count.Equals(1));
        }
    }

    public interface IInterface<T>
    {
        IInterface<T> SomeMethod();
        IInterface<T> SomeSecondMethod();
        List<T> GetData();
    }

    public class MyClass
    {
        public int Attribute { get; set; }
    }

    public class MyDependentClass
    {
        private readonly IInterface<MyClass> _test;

        public MyDependentClass(IInterface<MyClass> test)
        {
            _test = test;
        }

        public List<MyClass> DoTheThing()
        {
            return _test.SomeMethod().SomeSecondMethod().GetData();
        }
    }
...