Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
528 views
in Technique[技术] by (71.8m points)

c# - Moq a function with anonymous type

I'm trying to mock this method

Task<TResult> GetResultAsync<TResult>(Func<string, TResult> transformFunc)

like this

iMock.Setup(m => m.GetResultAsync(It.IsAny<Func<string, object>>())).ReturnsAsync(new { isPair = false });

The method to test doing the call passing an anonymous type to the generic parameter like this

instance.GetResultAsync(u => new {isPair = u == "something" }) //dont look at the function return because as generic could have diferent implementations in many case

Moq never matches my GetResultAsync method with the parameters sent.

I'm using Moq 4

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The anonymous type is going to cause you problems. You need a concrete type for this to work.

The following example worked when I changed

instance.GetResultAsync(u => new {isPair = u == "something" })

to

instance.GetResultAsync(u => (object) new {isPair = u == "something" })

Moq is unable to match the anonymous type and that is why you get null when called.

[TestClass]
public class MoqUnitTest {
    [TestMethod]
    public async Task Moq_Function_With_Anonymous_Type() {
        //Arrange
        var expected = new { isPair = false };

        var iMock = new Mock<IService>();
        iMock.Setup(m => m.GetResultAsync(It.IsAny<Func<string, object>>()))
            .ReturnsAsync(expected);

        var consumer = new Consumer(iMock.Object);

        //Act   
        var actual = await consumer.Act();

        //Assert
        Assert.AreEqual(expected, actual);
    }

    public interface IService {
        Task<TResult> GetResultAsync<TResult>(Func<string, TResult> transformFunc);
    }

    public class Consumer {
        private IService instance;

        public Consumer(IService service) {
            this.instance = service;
        }

        public async Task<object> Act() {
            var result = await instance.GetResultAsync(u => (object)new { isPair = u == "something" });
            return result;
        }
    }
}

if the code calling the GetResultAsync is dependent on using the anonymous type then what you are trying to do with your test wont work with your current setup. You would probably need to provide a concrete type to the method.

[TestClass]
public class MoqUnitTest {

    [TestMethod]
    public async Task Moq_Function_With_Concrete_Type() {
        //Arrange
        var expected = new ConcreteType { isPair = false };

        var iMock = new Mock<IService>();
        iMock.Setup(m => m.GetResultAsync(It.IsAny<Func<string, ConcreteType>>()))
            .ReturnsAsync(expected);

        var sut = new SystemUnderTest(iMock.Object);

        //Act   
        var actual = await sut.MethodUnderTest();

        //Assert
        Assert.AreEqual(expected, actual);
    }

    class ConcreteType {
        public bool isPair { get; set; }
    }

    public interface IService {
        Task<TResult> GetResultAsync<TResult>(Func<string, TResult> transformFunc);
    }

    public class SystemUnderTest {
        private IService instance;

        public SystemUnderTest(IService service) {
            this.instance = service;
        }

        public async Task<object> MethodUnderTest() {
            var result = await instance.GetResultAsync(u => new ConcreteType { isPair = u == "something" });
            return result;
        }
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...