NSubstitute icon indicating copy to clipboard operation
NSubstitute copied to clipboard

Returns Func lambda

Open Rubenisme opened this issue 5 years ago • 1 comments

Not quite sure if this should go here or somewhere else... Function Returns with a lambda expression doesn't work with lambda expression parameters as Moq does. Like in the link, here's what I was doing:

    using NSubstitute;
    using System;
    using System.Collections.Generic;
    using Xunit;

    namespace DNB.Ceasar.Service.Domain.Service.Tests
    {
        public interface IResponseFactory
        {
            Response Create(string bizTalkId, IEnumerable<Document> documents, bool hasFatalError = false);
        }

        public class Document { }
        public class Response
        {
            private string someId;
            private IEnumerable<Document> documents;
            private bool someBool;

            public Response(string someId, IEnumerable<Document> documents, bool someBool)
            {
                this.someId = someId;
                this.documents = documents;
                this.someBool = someBool;
            }
        }

        public class Tests
        {
            private readonly IResponseFactory responseFactory;

            public Tests()
            {
                responseFactory = Substitute.For<IResponseFactory>();
            }

            [Fact]
            public void Process_Calls_Execution_Method()
            {
                //Arrange

                // this works:
                //Response ReturnThis(CallInfo ret) => new Response(ret[0] as string, ret[1] as IEnumerable<Document>, (bool) ret[2]);

                // this doesn't:
                Func<string, IEnumerable<Document>, bool, Response> ReturnThis = (string x, IEnumerable<Document> y, bool z) => new Response(x as string, y as IEnumerable<Document>, z);

                responseFactory.Create(Arg.Any<string>(), Arg.Any<IEnumerable<Document>>(), false)
                    .Returns(ReturnThis);

                // Act
                var something = responseFactory.Create("bla", new Document[] { }, false);

                // Assert
                Assert.IsType<Response>(something);
            }
        }
    }

Is there another way to do it without having to use the ugly and error prone array way? Ideally I'd like to do:

    .Returns((x, y, z) => new Response(x, y, z));

Thanks, I love NSubstitute, I don't want my coworkers to say something is better/more beautiful in Moq ;)!

Rubenisme avatar Mar 18 '19 20:03 Rubenisme

Is there another way to do it without having to use the ugly and error prone array way?

Yes, you can use the Arg<>() or ArgAt<>() methods exposed by the CallInfo object 😊


NSubstitute doesn't provide other syntax out of the box. To me the main issue is that our syntax dosn't let us offer you API like this. Instead, you would have to specify the argument values manually:

.Returns((string x, IEnumerable<Document> y, bool z) => new Response(x, y, z));

Given that argument types are not checked at the compilation time, it doesn't bring any practical value.

But anyway, you are free to create such an extension method in your project, if it helps NSubstitute shine for you 😉

zvirja avatar Mar 19 '19 21:03 zvirja