2017-08-08 2 views
4

Je suis nouveau sur Moq, et je veux l'utiliser comme un backing store pour les données - mais sans toucher à la base de données en direct.Comment effectuer des tests unitaires avec Entity Framework et Moq?

Ma configuration est la suivante:

  • A UnitOfWork contient tous les dépôts, et est utilisé pour l'accès aux données dans toute l'application.
  • Un référentiel représente un hook direct dans un DbSet, fourni par un DbContext.
  • Un DbContext contient tous les DbSets.

Voici mon test jusqu'à présent:

 // ARRANGE 
     var user = new User() 
     { 
      FirstName = "Some", 
      LastName = "Guy", 
      EmailAddress = "[email protected]", 
     }; 

     var mockSet = new MockDbSet<User>(); 
     var mockContext = new Mock<WebAPIDbContext>(); 

     mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object); 

     // ACT 
     using (var uow = UnitOfWork.Create(mockContext.Object)) 
     { 
      uow.UserRepository.Add(user); 
      uow.SaveChanges(); 
     } 

     // ASSERT 
     mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once()); 

Mon test semble réussir, car il peut vérifier qu'un utilisateur a été ajouté à la DbSet maquette - mais ce que je dois faire est d'obtenir effectivement ces données et effectuer d'autres affirmations sur ce (il s'agit juste d'un test ad-hoc).

S'il vous plaît, conseillez-moi, les frameworks de tests font leur tête. De plus, j'ai la possibilité de passer à d'autres frameworks de tests s'ils sont plus faciles à utiliser.

Merci.

Mise à jour: Voici mon code de travail.

test unitaire

 // ARRANGE 
     var user = new User() 
     { 
      FirstName = "Some", 
      LastName = "Guy", 
      EmailAddress = "[email protected]", 
     }; 

     var mockSet = new MockDbSet<User>(); 
     var mockContext = new Mock<WebAPIDbContext>(); 

     mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object); 

     // ACT 
     using (var uow = UnitOfWork.Create(mockContext.Object)) 
     { 
      uow.UserRepository.Add(user); 
      uow.SaveChanges(); 
     } 

     // ASSERT 
     mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once()); 

     // TODO: Further assertations can now take place by accessing mockSet.BackingStore. 
    } 

MockDbSet

class MockDbSet<TEntity> : Mock<DbSet<TEntity>> where TEntity : class 
{ 
    public ICollection<TEntity> BackingStore { get; set; } 

    public MockDbSet() 
    { 
     var queryable = (this.BackingStore ?? (this.BackingStore = new List<TEntity>())).AsQueryable(); 

     this.As<IQueryable<TEntity>>().Setup(e => e.Provider).Returns(queryable.Provider); 
     this.As<IQueryable<TEntity>>().Setup(e => e.Expression).Returns(queryable.Expression); 
     this.As<IQueryable<TEntity>>().Setup(e => e.ElementType).Returns(queryable.ElementType); 
     this.As<IQueryable<TEntity>>().Setup(e => e.GetEnumerator()).Returns(() => queryable.GetEnumerator()); 

     // Mock the insertion of entities 
     this.Setup(e => e.Add(It.IsAny<TEntity>())).Returns((TEntity entity) => 
     { 
      this.BackingStore.Add(entity); 

      return entity; 
     }); 

     // TODO: Other DbSet members can be mocked, such as Remove(). 
    } 
} 
+0

Montrez votre code pour le jeu maquette db. Vous avez juste besoin de créer une collection pour faire office de backing store et de simuler l'énumération db définie avec la collection de sauvegarde. – Nkosi

+0

Désolé à ce sujet. J'ai mis à jour mon message. MockDbSet n'a pas été testé, car je ne suis pas tout à fait sûr comment tout cela s'accorde. Je doute que la variable "queryable" fonctionne de cette façon pour un DbSet. Comment pourrais-je créer une collection pour faire office de backing store en se connectant au simulacre de DbSet? – Rhonage

Répondre

5

Il vous suffit de créer une collection pour agir en tant que magasin de support et se moquer de l'ensemble énumération db avec la collection de support

public class MockDbSet<TEntity> : Mock<DbSet<TEntity>> where TEntity : class { 
    public MockDbSet(List<TEntity> dataSource = null) { 
     var data = (dataSource ?? new List<TEntity>()); 
     var queryable = data.AsQueryable(); 

     this.As<IQueryable<TEntity>>().Setup(e => e.Provider).Returns(queryable.Provider); 
     this.As<IQueryable<TEntity>>().Setup(e => e.Expression).Returns(queryable.Expression); 
     this.As<IQueryable<TEntity>>().Setup(e => e.ElementType).Returns(queryable.ElementType); 
     this.As<IQueryable<TEntity>>().Setup(e => e.GetEnumerator()).Returns(() => queryable.GetEnumerator()); 
     //Mocking the insertion of entities 
     this.Setup(_ => _.Add(It.IsAny<TEntity>()).Returns((TEntity arg) => { 
      data.Add(arg); 
      return arg; 
     }); 

     //...the same can be done for other members like Remove 
    } 
} 

vous pouvez donc maintenant utiliser une liste pour contenir les données

// ARRANGE 
var dataSource = new List<User>(); //<-- this will hold data 
var user = new User() 
{ 
    FirstName = "Some", 
    LastName = "Guy", 
    EmailAddress = "[email protected]", 
}; 

var mockSet = new MockDbSet<User>(dataSource); 
var mockContext = new Mock<WebAPIDbContext>(); 

mockContext.Setup(c => c.Set<User>()).Returns(mockSet.Object); 

// ACT 
using (var uow = UnitOfWork.Create(mockContext.Object)) 
{ 
    uow.UserRepository.Add(user); 
    uow.SaveChanges(); 


    // ASSERT 
    mockSet.Verify(u => u.Add(It.IsAny<User>()), Times.Once()); 
    Assert.IsTrue(dataSource.Contains(user)); //<-- shows mock actually added item 
    Assert.IsTrue(uow.UserRepository.Any(u => u == user)); //<-- show you can actually query mock DbSet 
}