Search code examples
c#unit-testingmoqfluent

Mocking a Fluent interface using Moq


I have looked at a number of questions here on this subject but none seem to address the issue I'm having.

I've got code that looks a bit like this...

IBaseDataCollector<MyClass> myDataCollector;

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

systemUnderTest = new Thing(myDataCollector.Object);

And in my Thing class...

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

where both SomeMethod() and SomeSecondMethod() return this (ie the instance of myDataCollector)

When I run my test I get a NullReferenceException on the like where I call myDataCollector.

I tried adding this in my test setup...

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

but that wouldn't even compile, complaining that it "Could not resolve method 'Returns(IBaseDataCollector)'"

Now, if I refactor my Thing class to read...

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

my test executes properly.

If this was it, I'd just refactor my code and get on with life, but, in reality, I need to call my code inside a SelectMany call...

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

Again, I know I could replace the SelectMany with, say, a ForEach and manually populate the collection with the results of each iteration of the call to GetData() so that I can get rid of the fluent element of the calls, but this means refactoring the code just to make the tests work, which feels wrong.

How should I be calling Setup() on my Mocked objects to make my fluent calls work?


Solution

  • Take a look at the following test code (I've invented some details to fill in the blanks). The mocked object instance should be available as a value to return from its own methods as shown.

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