3 votes

Essayer de simuler une requête IQueryable d'Entity Framework

J'essaie de tester qu'une requête n'est pas sensible à la casse. Ce code de production fonctionne :

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

Je n'arrive pas à faire fonctionner le test unitaire. Ma première tentative a échoué parce que je crois que la liste était IEnumerable au lieu de IQueryable . Cependant, ma tentative de IQueryable ne passe pas. La requête est sensible à la casse, et je ne veux pas qu'elle le soit. Voici ce que j'ai fait pour y remédier 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));
}

Qu'est-ce que je rate ?

Remarque : le getter pour EEntry.Id renvoie l'information suivante .ToUpper() . Le code de production ignore correctement cela. Le code de test ne le fait pas.

0voto

Bruno Points 182

On dirait que tu n'utilises pas employeeId1Output n'importe où, mais vous affirmez qu'il devrait être dans le payEntryRecords . En se basant sur votre code, il semble que vous devriez affirmer si employeeId1Input est en payEntryRecords à la place. Vous ajoutez explicitement employeeId1Input à votre payEntries objet.

0voto

Steve Py Points 2155

La nature insensible à la casse des comparaisons de chaînes de caractères dépend de votre fournisseur de base de données. SQL Server compare les chaînes de caractères sans tenir compte de la casse, alors que PostgreSQL, je crois, ne le fait pas.

Donc si votre code logique fait employeeIds.Contains(e.Id) EF transmettra la logique équivalente à la base de données. En remplaçant cela par un Mock et un List<T>.AsQueryable() En effet, C# traitera les chaînes de caractères comme sensibles à la casse, alors que le serveur SQL ne s'en soucie pas. Les clauses IN() et les comparaisons de chaînes sont insensibles à la casse.

J'envisagerais d'utiliser l'exemple ci-dessous, ou quelque chose de similaire, pour garantir que la comparaison des chaînes de caractères est effectuée sans tenir compte de la casse. Cela devrait fonctionner avec tous les fournisseurs de bases de données et être plus facile à placer avec des données factices.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X