Méthodes Moq ‘où Expression <Func > sont passées en parameters

Je suis très novice dans les tests unitaires et les moqueries! J’essaie d’écrire des tests unitaires qui couvrent un code qui interagit avec un magasin de données. L’access aux données est encapsulé par IRepository:

interface IRepository { .... IEnumerable FindBy(Expression<Func> predicate); .... } 

Le code que j’essaye de tester, utilisant une implémentation concrète d’IoC’d d’IRepository ressemble à ceci:

 public class SignupLogic { private Repository repo = new Repository(); public void AddNewCompany(Company toAdd) { Company existingCompany = this.repo.FindBy(c => c.Name == toAdd.Name).FirstOrDefault(); if(existingCompany != null) { throw new ArgumentException("Company already exists"); } repo.Add(Company); repo.Save(); } } 

Pour tester la logique de SignupLogic.AddNewCompany () plutôt que la logique et le référentiel concret, je mets en cache IRepository et le transmet à SignupLogic. Le référentiel simulé ressemble à ceci:

 Mock repoMock = new Mock(); repoMock.Setup(moq => moq.FindBy(c => c.Name == "Company Inc").... 

qui renvoie un IEnumberable en mémoire contenant un object Company avec le nom défini sur “Company Inc”. Le test unitaire qui appelle SignupLogic.AddNewCompany configure une société avec des détails en double et tente de le transmettre, et j’affirme qu’une exception ArgumentException est lancée avec le message “La société existe déjà”. Ce test ne passe pas.

Déboguer à travers le test unitaire et AddNewCompany () au fur et à mesure de son exécution, il semblerait que existingCompany est toujours nul. En désespoir de cause, j’ai constaté que si je mets à jour SignupLogic.AddNewCompany () pour que l’appel à FindBy ressemble à ceci:

 Company existingCompany = this.repo.FindBy(c => c.Name == "Company Inc").FirstOrDefault(); 

le test réussit, ce qui me suggère que Moq ne répond qu’au code qui est exactement le même que celui que j’ai configuré dans mon appareil de test. De toute évidence, ce n’est pas particulièrement utile pour tester que toute entreprise dupliquée est rejetée par SignupLogic.AddNewCompany.

J’ai essayé de configurer moq.FindBy (…) pour utiliser “Is.ItAny”, mais cela ne provoque pas non plus le test.

D’après tout ce que je lis, il semble que tester des expressions comme j’essaye ne soit pas réellement faisable avec Moq ici. C’est possible? S’il vous plaît aider!

Il est probablement exact que seule une Expression avec la même structure (et les mêmes valeurs littérales) correspondra. Je suggère que vous utilisiez la surcharge de Returns() qui vous permet d’utiliser les parameters avec lesquels la maquette est appelée:

 repoMock.Setup(moq => moq.FindBy(It.IsAny>>()) .Returns((Expression> predicate) => ...); 

Dans ... , vous pouvez utiliser des predicate pour renvoyer les sociétés correspondantes (et même lancer une exception si les sociétés correspondantes ne correspondent pas à vos attentes). Pas très joli, mais je pense que ça va marcher.

Vous devriez pouvoir utiliser It.IsAny<>() pour accomplir ce que vous cherchez à faire. Avec It.IsAny<>() vous pouvez simplement ajuster le type de retour de votre configuration pour tester chaque twig de votre code.

 It.IsAny>>() 

Premier test, retourne une entreprise quel que soit le prédicat qui provoquera l’exception à lancer:

 var repoMock = new Mock>(); repoMock.Setup(moq => moq.FindBy(It.IsAny>>())).Returns(new List{new Company{Name = "Company Inc"}}); var signupLogic = new SignupLogic(repoMock.Object); signupLogic.AddNewCompany(new Company {Name = "Company Inc"}); //Assert the exception was thrown. 

Deuxième test, définissez le type de retour comme une liste vide qui provoquera l’appel.:

 var repoMock = new Mock>(); repoMock.Setup(moq => moq.FindBy(It.IsAny>>())).Returns(new List()); var signupLogic = new SignupLogic(repoMock.Object); signupLogic.AddNewCompany(new Company {Name = "Company Inc"}); repoMock.Verify(r => r.Add(It.IsAny()), Times.Once()); 

Normalement, vous ne vous moquez que des types que vous possédez. Ceux que vous ne possédez pas, ne devraient pas être ridiculisés en raison de diverses difficultés. Les expressions moqueuses – comme le nom de votre question l’indique – ne sont donc pas la solution.

Dans le cadre de Moq. Il est important de mettre .Returns() pour les fonctions sinon il ne correspond pas. Donc, si vous ne l’avez pas fait, c’est votre problème.

 repoMock.Setup(moq => moq.FindBy(c => c.Name == "Company Inc").Returns(....