Stuart Hemming
Stuart Hemming

Reputation: 1663

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?

Upvotes: 3

Views: 1238

Answers (1)

Adam
Adam

Reputation: 3847

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

Upvotes: 4

Related Questions