【问题标题】:How can the equality operator for byte arrays be faked in Linq-to-Entities while unit testing?在单元测试时,如何在 Linq-to-Entities 中伪造字节数组的相等运算符?
【发布时间】:2014-05-26 16:34:58
【问题描述】:

我的数据库中有一些varbinary 表列,我需要用字节数组测试它们是否相等,所有这些都通过实体框架和Linq-to-Entities 发生。对于 Linq-to-Objects,这很容易通过 SequenceEquals 扩展方法实现,但不幸的是 EF 不支持它,因此我依赖正确转换为 SQL 查询的 == 运算符。

例如

byte[] deviceId = GetDeviceId();

Device device = _deviceRepository.QueryAll() //backed by a DbContext, returns IQueryable<Device>
.Include(d => d.RelatedEntity1)
.Include(d => d.RelatedEntity2)
.Include(d => d.RelatedEntityEtc)
.FirstOrDefault(d => d.DeviceUniqueIdentifier == deviceId && ...);

LoginUserOnDevice(device);

但是,问题是,在对涉及 Linq-to-Entities 查询的代码段进行单元测试时,使用伪造的 _deviceRepository,我使用普通的 List&lt;T&gt; 通过 .AsQueryable() 转换为 @ 987654328@,相等运算符应用其原始语义,即引用相等,因此比较显然失败。当然,严格来说,这不会发生在单元测试中,而是在不再针对 SQL 数据源执行 linq 查询的任何情况下。

这里的最佳方法是什么?最好不更改查询代码,以便在查询真实数据库(使用 EF 6)和单元测试时都能正确运行。在我的场景中,通过在 Includes 之后调用 .ToList() 或类似的任何内容将整个集合具体化到内存中是不可能的。

【问题讨论】:

    标签: c# .net entity-framework unit-testing linq-to-entities


    【解决方案1】:

    你可以而且应该避免这整件事。您应该让它简单地返回您的测试所需的数据,而不是对您的假存储库执行查询;否则,您基本上是在尝试测试 EF 是否正常工作(即使在这里您将其模拟出来)。

    这是用假货替换该存储库的主要原因之一:您希望无需调用数据库来获取数据,而是返回一些预定义的数据集,您可以使用这些数据集来测试您的单元的工作情况。

    如果您真的想测试您的 LINQ 查询,那么您首先要查看一个集成测试:您正在测试您的系统如何与外部系统交互。此时很明显,您也不需要虚假存储库,因为这不会测试与您的(开发)数据库的交互。

    使用妨碍正确测试的遗留代码确实是一个障碍。正如您所注意到的,您不能再按照您想要的方式进行操作(以及您通常的操作方式:使用相同的 LINQ 查询从您的存储库返回模拟数据)。

    如果 可以使查询按照您想要的方式运行(我非常不确定),这太麻烦了。我建议您改为模拟对存储库的调用,而不是对存储库本身进行存根。将查询放在存储库之外,责任链已被打破,因此更改存储库无法解决您的问题。

    我不完全确定这是否会按照我想要的方式运行,所以稍微玩一下,但我相信应该这样做(使用起订量):

    var device = new Device(id: 5, name: "washingmachine", price: 5000);
    var repository = new Mock <IDeviceRepository>();
    repository.Setup(x => x.QueryAll())
              .Returns(device);
    

    如果您现在使用 LINQ 查询执行测试,它将忽略它所做的任何事情,而是返回您预定义的 device

    【讨论】:

    • 这是一个很好的建议,如果这是我项目生命周期的早期阶段,我可能会使用适当的方法将存储库更改为严格返回 IEnumerable&lt;T&gt; 而不是 IQueryable&lt;T&gt;,但现在是有点晚了。这是我为将域模型与实体模型高度耦合所付出的代价。此外,我实际上并没有测试 EF 查询,我实际上想删除设备存储库,以便查询本身不会妨碍,然后我使用检索到的(假)设备来进一步断言。跨度>
    • 您能用更详细的代码示例编辑您的帖子吗?目前尚不清楚此 LINQ 查询的确切位置。
    • 我在查询中添加了更多上下文,但我认为这仍然是相关的。封装此代码的方法是一个公共方法,也将是单元测试的入口点。
    • @GabrielS.:添加了一些我认为应该解决问题的内容。
    • 非常感谢,但不幸的是,Include() 调用使这变得更加复杂 - 我必须模拟每个 Include() 调用,一次一个,否则 Moq 会抱怨。如您所想,结果将是丑陋的,超出任何可读性的希望。但这可能确实是一个解决方案,我会尝试看看它的可行性。
    猜你喜欢
    • 2023-04-03
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-30
    • 2011-07-31
    相关资源
    最近更新 更多