模拟和验证对包含 Expression> 参数的方法的调用

2024-03-13

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

完整源代码:

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)));
    }
}

当我执行单元测试时,它失败并出现错误:

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

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

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


As per 这个帖子 https://stackoverflow.com/questions/5032865/how-do-linq-expressions-determine-equality,比较Expression可能非常脆弱,因为默认值是通过引用的,并且需要寻找替代方案。但是,使用引用的方法,即通过简单ToString()表达式的比较Body,您可以像这样验证表达式:

 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());

(i.e Moq保留类型的调用参数列表Expression,就像可以在 a 中使用的任何其他类型的参数一样Verify or Setup)

Edit

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

模拟和验证对包含 Expression> 参数的方法的调用 的相关文章

  • 在 Jest 测试中设置时刻时区

    我有 util 函数 它以特定的日期格式解析给定的日期 即 2019 01 28 然后使用momentJS检索当天的开始并将其转换为 ISO 日期格式 dates js import moment from moment export co
  • 如果finally 块包含await,为什么*有时*不会在ThreadAbortException 上执行?

    UPDATE 我不认为这个问题是重复的ThreadAbortException最后可以跳过吗 https stackoverflow com questions 18002668 can threadabortexception skip
  • 从具有相同属性的另一个对象创建对象

    我有一个 C 对象 可以说有 20 个属性 它是数据契约的一部分 我还有另一个具有类似属性的业务实体 我想从响应对象中填充该实体 除了将一个对象的每个属性分配给另一个对象的相应属性之外 还有其他方法可以做到这一点吗 是的 看看自动映射器 h
  • 如何在 REST WCF 服务中接受任意 JSON 对象?

    我想实现这样的服务方法 OperationContract WebInvoke RequestFormat WebMessageFormat Json ResponseFormat WebMessageFormat Json public
  • 在.net中的lock语句中调用Thread.Sleep()

    我想知道在已经获取监视器的线程上调用 Thread Sleep 是否会在进入睡眠状态之前释放锁 object o new object Montior Enter o Thread Sleep 1000 Monitor Exit o 当线程
  • 使用 SQLite 测试 NHibernate“没有这样的表” - 生成模式

    我正在尝试使用内存中的 SQLite 数据库来测试 NHibernate 提供的数据层 我读过很多关于如何进行此设置的博客和文章 但我现在很困惑为什么它不起作用 问题 当我运行单元测试时 我收到错误 没有这样的表 学生 我读过的文章表明这
  • CMake - 作为构建过程的一部分运行测试并将标准输出捕获到文件

    我们有几个单元测试 我们希望将其作为构建过程的一部分运行 为了实现这一目标 我有一个帮助程序脚本 它创建一个运行测试的自定义命令 如果成功 则创建一个文件 test name passed 然后我添加一个自定义目标 test name ru
  • 进程间并发文件写入

    我需要将不同进程的日志数据写入单个文件 我正在使用 Windows Mutex 它需要公共语言运行时支持 Mutex m gcnew Mutex false MyMutex m gt WaitOne File Open and Write
  • 在 C++/CLI 中创建时初始化静态字典

    今天我看到创建静态字典并初始化它的 C 代码 public static readonly Dictionary
  • R testthat 单元测试数据和辅助函数约定

    我正在编写一个 R 包 并使用 testthat 进行单元测试 我的许多单元测试都是为了测试适用于我的包特定对象的功能 对于这些测试 我创建了一个辅助函数来设置模拟对象 我还有一些其他辅助函数来减少单元测试中的代码量 目前这些辅助函数在我的
  • ToUpperInvariant() – MSDN 的建议是否错误?

    In 在 NET Framework 中使用字符串的最佳实践 https msdn microsoft com en us library dd465121 v vs 110 aspx 字符串比较OrdinalIgnoreCase http
  • 找不到文件异常..但它就在那里

    嘿 这将是那些愚蠢的问题之一 我试图在本地系统上获取一个文件 但我不断收到FileNotFoundException thrown 请有人纠正我 if File Exists C logs hw healthways prod 2009 0
  • 获取计算机的MAC地址

    我想使用c 访问计算机的mac地址 我使用以下代码来访问 mac 地址 但此代码存在一些问题 Code 1 foreach NetworkInterface nic in NetworkInterface GetAllNetworkInte
  • MSI 和 EXE 安装程序有什么区别,我应该选择哪一个? [复制]

    这个问题在这里已经有答案了 可能的重复 msi 和 setup exe 文件之间有什么具体区别 https stackoverflow com questions 1789530 what are the specific differen
  • 测试 - 存根服务方法未定义

    我已经在非常简单的代码上编写了一个非常简单的测试 但由于某种原因存根服务方法未定义 当我使用 Jasmine Spy 时 它可以工作 但对于这样一个简单的任务 有人可以解释一下为什么会发生这种情况吗 我删除了 import 语句只是为了减少
  • xCode 7.1 中警报的 UITesting

    我正在 xCode 7 1 中编写 UITests 并且在测试警报时遇到问题 在我的情况下允许通知 创建测试时 xCode 会写入以下代码 app alerts U201cAppName U201d Would Like to Send Y
  • 如何让实体框架初始化新创建的实体上的集合?

    我正在尝试用一些测试数据来种子我的数据库IDatabaseIntialiser像这样 protected override void Seed BlogDataContext context
  • SignTool 错误:访问被拒绝

    我尝试在安装了 VS2010 的 Windows Server 2008 R2 x64 上使用新的代码签名证书对 NET 应用程序进行authenticode 签名 但 SignTool 始终响应访问被拒绝 SignTool exe sig
  • 如何将 Metro 应用部署到桌面?

    我正在尝试将我的 C 应用程序部署到我的 Windows 8 Metro 桌面 我可以在 bin 文件夹中看到部署的文件 但是当我尝试打开它们时 出现以下错误 该应用程序只能在 AppContainer 的上下文中运行 我检查了属性上下文菜
  • 具有多种类型的 C# 泛型类型推断

    我有以下通用方法 用于将一种类型的输入对象序列化为超类型 如下所示 public string SerialiseAs

随机推荐