Попытка макета IQueryable Entity Framework Query - PullRequest
0 голосов
/ 11 октября 2018

Я пытаюсь проверить, что запрос не чувствителен к регистру.Этот рабочий код работает:

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 возвращает .ToUpper().Производственный код правильно игнорирует это.Тестовый код отсутствует.

Ответы [ 2 ]

0 голосов
/ 12 октября 2018

Независимый от регистра характер сравнения строк зависит от поставщика вашей базы данных.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);
  }
}
0 голосов
/ 11 октября 2018

Не похоже, что вы используете employeeId1Output где-либо, но вы утверждаете, что оно должно быть в payEntryRecords.Исходя из вашего кода, похоже, что вы должны утверждать, находится ли employeeId1Input в payEntryRecords.Вы явно добавляете employeeId1Input к вашему payEntries объекту.

...