首页 > 解决方案 > 试图模拟 IQueryable 实体框架查询

问题描述

我正在尝试测试查询是否不区分大小写。此生产代码有效:

public ILookup<string, EEntry> GetEEntries(int batchId, List<string> employeeIds)
{
  using (WithNoLock())
  {
    var result = from e in _entities.EEntries
                 where e.CPayBatchProcessId == batchId
                       && (!e.Blocked.HasValue || e.Blocked.Value != true)
                       && employeeIds.Contains(e.Id)
                 select e;

    return result.ToLookup(e => e.Id, StringComparer.OrdinalIgnoreCase);
  }
}

我无法让单元测试工作。我的第一次尝试失败了,因为我相信该列表IEnumerable不是IQueryable. 但是,我的尝试并IQueryable没有通过。该查询区分大小写,我不希望这样。这就是我所做的IQueryable

[TestCase("abc", "ABC")]
public void EEntriesAreCaseInsensitive(string employeeId1Input, string employeeId1Output)
{
  var payEntries = new List<EEntry>
  {
    new EEntry() {CPayBatchProcessId = 8, Id = employeeId1Input},
    new EEntry() {CPayBatchProcessId = 8, Id = "123"}
  }.AsQueryable();

  var payEntriesDbSet = new Mock<DbSet<EEntry>>();
  payEntriesDbSet.As<IQueryable<EEntry>>().Setup(x => x.Provider).Returns(payEntries.Provider);
  payEntriesDbSet.As<IQueryable<EEntry>>().Setup(x => x.Expression).Returns(payEntries.Expression);
  payEntriesDbSet.As<IQueryable<EEntry>>().Setup(x => x.ElementType).Returns(payEntries.ElementType);
  payEntriesDbSet.As<IQueryable<EEntry>>().Setup(x => x.GetEnumerator()).Returns(payEntries.GetEnumerator);

  var context = new Mock<ISomeContext>();
  context.Setup(x => x.EEntries).Returns(payEntriesDbSet.Object);

  var employeeIds = new List<string>() { "aBc", "dEf", "gHi" };

  var repo = new EEntriesRepository(context.Object);
  var payEntryRecords = repo.GetEEntries(8, employeeIds);

  Assert.IsTrue(payEntryRecords.Contains(employeeId1Output));
}

我错过了什么?

注意: EEntry.Id 的 getter 返回.ToUpper(). 生产代码正确地忽略了这一点。测试代码没有。

标签: c#entity-frameworklinqiqueryable

解决方案


字符串比较不区分大小写的性质取决于您的数据库提供程序。SQL Server 将比较字符串不区分大小写,而我相信 PostgreSQL 之类的则不会。

因此,如果您的代码逻辑确实如此employeeIds.Contains(e.Id),EF 会将等效逻辑传递给数据库。当用 Mock 和 替换它时List<T>.AsQueryable(),C# 会将字符串视为区分大小写,而 SQL Server 不关心。IN() 子句和字符串比较不区分大小写。

我会考虑使用以下或类似的方法来确保执行字符串比较不区分大小写。这应该适用于数据库提供程序,并且可以更好地处理模拟数据。

public ILookup<string, EEntry> GetEEntries(int batchId, List<string> employeeIds)
{
  if(employeeIds == null) throw new ArgumentNullException("employeeIds");

  employeeIds = employeeIds.ConvertAll(x => x.ToUpper());
  using (WithNoLock())
  {
    var result = from e in _entities.EEntries
                 where e.CPayBatchProcessId == batchId
                       && (!e.Blocked.HasValue || e.Blocked.Value != true)
                       && employeeIds.Contains(e.Id.ToUpper())
                 select e;

    return result.ToLookup(e => e.Id, StringComparer.OrdinalIgnoreCase);
  }
}

推荐阅读