简体   繁体   English

带有约束的Moq表达式…It.Is <Expression<Func<T, bool> &gt;&gt;

[英]Moq Expression with Constraint … It.Is<Expression<Func<T, bool>>>

Ok, I am having a hard time trying to figure out how to setup a moq for a method that takes in an expression. 好的,我很难解决如何为采用表达式的方法设置最小起订量的问题。 There are a lot of examples out there of how to to It.IsAny<>... that is not what I am after. 有很多关于如何实现它的示例。IsAny <> ...这不是我所追求的。 I am after doing with a constraint, so It.Is<>. 我在处理约束之后,所以是It.Is <>。 I have set it up but it never returns the value I have asked it to return. 我已经设置了它,但是它从不返回我要求它返回的值。

// Expression being setup
Expression<Func<UserBinding, bool>> testExpression = binding =>
binding.User.Username == "Testing Framework";


// Setup of what expression to look for. 
 this.bindingManager.Setup(
            c => c.GetUserBinding(It.Is<Expression<Func<UserBinding, bool>>>
(criteria => criteria == testExpression)))
            .Returns(new List<UserBinding>() { testBinding }.AsQueryable());

// Line of code call from within the class being tested. So this is being mocked and should return the defined object when the same lambda is passed in.
 this.bindingManager.GetUserBinding(b => b.User.Username == username)
                .SingleOrDefault();

// class under test. So for the test this is being called. 
// so this is the method being called and inside this method is where the binding manager is being mocked and called. 
var response = this.controller.SendMessage(message, true).Result;

        response.StatusCode.Should().Be(HttpStatusCode.BadRequest);

 // inside the controller.SendMessage method this method is called with the lambda expression. I have verified the usernames match but when the setup is It.Is this returns null instead of the object setup in the "setup" call. 
this.bindingManager.GetUserBinding(b => b.User.Username == username)
                .SingleOrDefault();

If I change the setup to It.IsAny... It works and returns the expected object setup in the "returns" method. 如果我将设置更改为It.IsAny ...,它将起作用,并在“返回”方法中返回预期的对象设置。

I have found a few examples of how to do this on the web one is doing it this way the other is using compile but I can't get that to work either. 我已经找到了一些有关如何在Web上执行此操作的示例,一个示例是这样做的,另一个示例是使用编译的,但是我也无法使它正常工作。 How do you get this to work for a specific expression? 如何使它适用于特定的表达式?

Update with working solution based on answer 根据答案更新工作解决方案


@carlos-alejo got me going in the right direction or at least kicked me back to the Compile action. @ carlos-alejo让我朝正确的方向前进,或者至少让我踢回了“编译”操作。 I was thinking about it wrong. 我在想错了。 I have the solution working now based on using compile. 我现在基于使用编译的解决方案。 The key thing to understand about compile is you are giving it an object by which to evaluate/generate the expression for. 了解编译的关键是为它提供一个对象,通过该对象可以评估/生成表达式。

So in my case if some one is giving me an expression like this: 因此,在我的情况下,如果有人给我这样的表达:

binding => binding.User.Username == "Testing Framework";

I need to have a UserBinding like this: 我需要像这样的UserBinding:

var testBinding = new UserBinding { Binding = new Binding { Name = "Default binding" }, Domain = "test.com", User = new User() { Username = "Testing Framework" } };

I can then create my "setup" call like this: 然后,我可以像这样创建“设置”调用:

this.bindingManager.Setup(c => c.GetUserBinding(It.Is<Expression<Func<UserBinding, bool>>>(y => y.Compile()(testBinding))))
        .Returns(new List<UserBinding>() { testBinding }.AsQueryable());

This works and in my case returns me back the test binding object as I have setup. 这可以正常工作,在我的情况下,设置完成后,我会返回测试绑定对象。 If you change the testBinding to be (notice I changed the user name) : 如果将testBinding更改为(注意,我更改了用户名)

    var testBinding = new UserBinding { Binding = new Binding { Name = "Default binding" }, Domain = "test.com", User = new User() { Username = "Testing Framework2" } };

It will not work because the code inside my system under test generates an expression looking for "Test Framework" 这将无法正常工作,因为被测系统内部的代码会生成一个寻找“ Test Framework”的表达式

Maybe it was just me not connecting the dots on this but hopefully it helps others. 也许只是我没有在这点上串连,但希望它能对其他人有所帮助。

It seems that the real problem here is how to compare two lambda expressions, as you try to do in the It.Is<Expression<Func<UserBinding, bool>>> (criteria => criteria == testExpression) clause. 似乎这里真正的问题是,如您在It.Is<Expression<Func<UserBinding, bool>>> (criteria => criteria == testExpression)子句中尝试的那样,如何比较两个lambda表达式。 Using @neleus's answer to this question , I could came up with this test that actually passes: 使用@neleus对这个问题的答案,我可以想出这个实际通过的测试:

readonly Mock<IBindingManager> bindingManager = new Mock<IBindingManager>();

[Test]
public void TestMethod()
{
    Expression<Func<string, bool>> testExpression = binding => (binding == "Testing Framework");

    bindingManager.Setup(c => c.GetUserBinding(It.Is<Expression<Func<string, bool>>>(
        criteria => LambdaCompare.Eq(criteria, testExpression)))).Returns(new List<string>());

    var oc = new OtherClass(bindingManager.Object);

    var actual = oc.Test(b => b == "Testing Framework");

    Assert.That(actual, Is.Not.Null);
    bindingManager.Verify(c => c.GetUserBinding(It.Is<Expression<Func<string, bool>>>(
        criteria => LambdaCompare.Eq(criteria, testExpression))), Times.Once());
}

Please note the use of the LambdaCompare.Eq static method to compare that the expressions are the same. 请注意,使用LambdaCompare.Eq静态方法来比较表达式是否相同。 If I compare the expressions just with == or even Equals , the test fails. 如果仅将表达式与==或什至Equals进行比较,则测试将失败。

When I was looking for the way to to mock Where() and filter some data, in code under tests looks like: 当我寻找模拟Where()并过滤一些数据的方法时,在测试中的代码如下:

Repository<Customer>().Where(x=>x.IsActive).ToList() 

I could design such example based on answers form others: 我可以根据其他人的答案设计这样的示例:

 var inputTestDataAsNonFilteredCustomers = new List<Customer> {cust1, cust2};
 var customersRepoMock = new Mock<IBaseRepository<Customer>>();

                IQueryable<Customer> filteredResult = null;
                customersRepoMock.Setup(x => x.Where(It.IsAny<Expression<Func<Customer, bool>>>()))
                    .Callback((Expression<Func<Customer, bool>>[] expressions) =>
                    {
                        if (expressions == null || expressions.Any() == false)
                        {
                            return;
                        }
                        Func<Customer, bool> wereLambdaExpression = expressions.First().Compile();  //  x=>x.isActive is here
                        filteredResult = inputTestDataAsNonFilteredCustomers.Where(wereLambdaExpression).ToList().AsQueryable();// x=>x.isActive was applied
                    })
                   .Returns(() => filteredResult.AsQueryable());

Maybe it will be helpful for feather developers. 也许对羽毛开发者会有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM