0

I have the following Interface that is used to DI and IOC webservice clients

    public interface IWcfServiceClientProvider <TContract>: IDisposable where TContract: class
{

    TResult Execute<TResult>(Expression<Func<TContract, TResult>> expression);
    TResult Execute<TResult>(Expression<Func<TContract, TResult>> expression, bool closeConnection = true);

    void Execute(Expression<Action<TContract>> expression);
    void Execute(Expression<Action<TContract>> expression, bool closeConnection = true);


}

In my test class I have the following:

 List<BaseLookup> myList = new List<BaseLookup> { 
                        new BaseLookup { Id =1, Code = "1001"},
                        new BaseLookup { Id =2, Code = "1002"},
                        new BaseLookup { Id =3, Code = "1003"}};

In my test method

 Mock<IWcfServiceClientProvider<ILookupService>> lookupServiceClinetProvider = new Mock<IWcfServiceClientProvider<ILookupService>>();

 var controller = new ElectorSearchController(lookupServiceClinetProvider.Object);
 lookupServiceClinetProvider.Setup(mock => mock.Execute(lookup => lookup.GetList(10))).Returns(myList).Verifiable();

  var list = controller.testMethod();

  lookupServiceClinetProvider.VerifyAll();

list will only have value when the parameter for GetList is set to 10 i.e GetList(10) Not GetList(i) where i=10

The following works

lookupServiceClinetProvider.Setup(mock => mock.Execute(It.IsAny<Expression<Func<ILookupService, List<BaseLookup>>>>(), true )).Returns((List<BaseLookup>)myList).Verifiable();

But I want to mock the call for GetList and not any call to Execute. If that works, then I can filter the values in the Return method

4

1 回答 1

0

As an interim solution I wrote a simple brute-force solution to compare expressions following:

    public static bool ExpressionMatcher<TIn, TResult>(Expression<Func<TIn, TResult>> expr1, Expression<Func<TIn, TResult>> expr2)
    {
        if (expr1 == null || expr2 == null)
        {
            return false;
        }

        if (expr1 == expr2)
        {
            return true;
        }

        if (expr1.Type != expr2.Type)
        {
            return false;
        }

        if (expr1.Body == expr2.Body)
        {
            return true;
        }

        if (expr1.Body.NodeType != expr2.Body.NodeType)
        {
            return false;
        }

        if (expr1.Body.NodeType == ExpressionType.Call)
        {
            dynamic expr1Body = expr1.Body;
            dynamic expr2Body = expr2.Body;

            if (expr1Body.Method.Name == expr2Body.Method.Name &&
                expr1Body.Method.ReturnType == expr2Body.Method.ReturnType)
            {
                if (expr1Body.Arguments == null && expr2Body.Arguments == null)
                {
                    return true;
                }

                if (expr1Body.Arguments.Count != expr2Body.Arguments.Count)
                {
                    return false;
                }

                return true;
            }
        }

        return false;

    }

I used the following to call it

Expression<Func<ILookupService, List<BaseLookup>>> expr = lookup => lookup.GetMyList(It.IsAny<long>());
.Setup(mock => mock.Execute(It.Is<Expression<Func<ILookupService, List<BaseLookup>>>>(method => ExpressionMatcher(method, expr))))
.Returns(myList)
.Verifiable();

I don't need to check the arguments' type at this point. If you have a better answer, please let me know

于 2013-04-23T22:07:45.583 回答