模拟并验证对包含Expression< Func< T,bool>的方法的调用.范围 [英] Mocking and verifying call to method containing an Expression<Func<T,bool>> parameter

查看:112
本文介绍了模拟并验证对包含Expression< Func< T,bool>的方法的调用.范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Moq或RhinoMocks来模拟此接口,以验证是否将正确的表达式作为参数传递(并愿意切换到任何其他可以支持此功能的开源模拟库):

I would like to mock this interface using Moq or RhinoMocks for the purpose of verifying that the correct expression is passed as a parameter (and willing to switch to any other open source mocking library that can support this):

完整源代码:

public class Record
{
    public int RecordId { get; set; }
}

public interface IRepository
{
    void DeleteRecordsByFilter(Expression<Func<Record, bool>> filter);
}

public class MyClass
{
    private readonly IRepository _repo;

    public MyClass(IRepository repo)
    {
        _repo = repo;
    }

    public void DeleteRecords(int recordId)
    {
        _repo.DeleteRecordsByFilter(x => x.RecordId.Equals(recordId));
    }
}

[TestFixture]
public class MyFixture
{
    [Test]
    public void DeleteRecordsShouldCallDeleteRecordsByFilterOnRepo()
    {
        const int recordId = 10;

        var repo = new Mock<IRepository>();
        repo.Setup(method => method.DeleteRecordsByFilter(x => x.RecordId.Equals(recordId)));

        var sut = new MyClass(repo.Object);
        sut.DeleteRecords(recordId);

        repo.Verify(method => method.DeleteRecordsByFilter(x => x.RecordId.Equals(recordId)));
    }
}

当我执行单元测试时,它失败并显示以下错误:

When I execute the unit test it fails with the error:

Moq.MockException:预期对模拟至少调用一次, 但从未执行过:method => method.DeleteRecordsByFilter(x => x.RecordId.Equals(10))

Moq.MockException : Expected invocation on the mock at least once, but was never performed: method => method.DeleteRecordsByFilter(x => x.RecordId.Equals(10))

已配置的设置:方法=> method.DeleteRecordsByFilter(x => x.RecordId.Equals(10)),Times.Never

Configured setups: method => method.DeleteRecordsByFilter(x => x.RecordId.Equals(10)), Times.Never

执行的调用:IRepository.DeleteRecordsByFilter(x => x.RecordId.Equals(value(MyClass +<> c__DisplayClass0).recordId))

Performed invocations: IRepository.DeleteRecordsByFilter(x => x.RecordId.Equals(value(MyClass+<>c__DisplayClass0).recordId))

推荐答案

按照 this 后,Expression的比较可能非常脆弱,因为默认值是通过引用提供的,因此需要寻找替代方法.但是,使用引用的方法,即通过对表达式Body的简单ToString()比较,您可以像这样验证表达式:

As per this post, comparisons of Expression can be quite fragile, as the default is by reference, and alternatives need to be sought. However, using the referenced method, viz by simple ToString() comparison of the Expression Body, you can verify the expression like so:

 var _mock = new Mock<IInterfaceToBeMocked>();

 // "Act" step -> invoke your CUT, which in turn calls the mocked interface dependency
 // (Obviously your CUT will do this, but just to prove the point ...)
 _mock.Object.DeleteRecordsByFilter(x => x.RecordId.Equals(10));

 // Back to the unit test 
 Expression<Func<Record, bool>> goodComparison = x => x.RecordId.Equals(10);
 Expression<Func<Record, bool>> badComparison = x => x.RecordId > 10 && x.RecordId < 12;
 _mock.Verify(m => m.DeleteRecordsByFilter(
    It.Is<Expression<Func<Record, bool>>>(ex => ex.Body.ToString() == goodComparison.Body.ToString())), 
    Times.Once);
 _mock.Verify(m => m.DeleteRecordsByFilter(
    It.Is<Expression<Func<Record, bool>>>(ex => ex.Body.ToString() == badComparison.Body.ToString())),
    Times.Never());

(即Moq保留Expression类型的已调用参数的列表,就像可以在VerifySetup中使用的任何其他类型的参数一样)

(i.e Moq retains a list of invoked parameters of type Expression, just like any other type of parameter which can be used in a Verify or Setup)

编辑

上面的方法适用于琐碎的情况,其中表达式中没有外部变量或闭包变量,因此两个表达式都等效地序列化.在CUT将相同的表达式实例传递给依赖项的情况下,@ Oliver的引用相等性将起作用.但在一般情况下,您将需要确定2个表达式是否相等,例如用一组已知的输入和输出来调用这两个表达式(但这更多是与表达式/函数/Lambdas等价的问题有关,而不是Moq问题).

The above works for the trivial case where there are no external or closure variables in the expression and hence both expressions serialize equivalently. And the reference equality from @Oliver will work in the case where the CUT passes the same expression instance to the dependency. But in the general case, you would somehow need to determine whether 2 expressions are equivalent, e.g. to invoke both expressions with a set of known inputs and outputs (but this is more to do with the issue with the equivalence of Expressions / Functions / Lambdas - and not really a Moq issue).

这篇关于模拟并验证对包含Expression&lt; Func&lt; T,bool&gt;的方法的调用.范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆