2017-06-29 1 views
4

Je souhaite tester les méthodes de récupération à partir d'un référentiel dont le DbContext est raillé, mais je ne suis pas en mesure de définir les valeurs DbSet mockées dans le référentiel.Mocking DbSet <TEntity> dans le référentiel

Le dépôt ressemble à ceci:

public class ChangeLogRepository : Repository<ChangeLog>, IChangeLogRepository 
{ 
    public ChangeLogRepository(IDbContext context, long tenantId) : base(context, tenantId) 
    { 
    } 
} 

La classe de base:

public class Repository<TEntity> where TEntity : class { 
    protected readonly IDbContext Context; 
    protected DbSet<TEntity> Entities { get; set; } 
    public long TenantId { get; set; } 

    protected Repository(IDbContext context, long tenant) 
    { 
     Context = context; 
     TenantId = tenant; 
     Entities = Context.Set<TEntity>(); 
    } 
    public List<TEntity> GetAll() 
    { 
     return Entities.ToList(); 
    } 
    //.. 
} 

Last but not least, la classe de test:

[TestClass] 
public class ChangeLogRepository_Test 
{ 
    private ChangeLogRepository repository; 
    private List<ChangeLog> allTestData; 

    [TestInitialize] 
    public void TestInitialize() 
    { 
     var dbContext = new Mock<IDbContext>(); 
     allTestData = new List<ChangeLog>() { 
      new ChangeLog { Id = 10, EntityName = "User",PropertyName = "UserName",PrimaryKeyValue = 1,OldValue = "Max",NewValue = "Moritz",DateChanged = DateTime.Now,FieldType = ChangeLogFieldType.Default }, 
      new ChangeLog { Id = 10, EntityName = "User",PropertyName = "CreatedAt",PrimaryKeyValue =2,OldValue = "15/06/2017",NewValue = "15/06/2017",DateChanged = DateTime.Now,FieldType = ChangeLogFieldType.Date }, 
      new ChangeLog { Id = 10, EntityName = "Role",PropertyName = "RoleName",PrimaryKeyValue = 56,OldValue = "Admin",NewValue = "Administrator",DateChanged = DateTime.Now,FieldType = ChangeLogFieldType.Default }, 
     }; 
     var changelogs = MockDbSet(allTestData); 
     dbContext.Setup(m => m.Set<ChangeLog>()).Returns(() => changelogs); 
     repository = new ChangeLogRepository(dbContext.Object, 10); 
    } 

    [TestMethod] 
    public void Setup_Test() 
    { 
     Assert.AreEqual(repository.GetAll(), allTestData); 
    } 
    private static DbSet<T> MockDbSet<T>(IEnumerable<T> list) where T : class, new() 
    { 
     IQueryable<T> queryableList = list.AsQueryable(); 
     Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>(); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType); 
     dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(queryableList.GetEnumerator()); 
     return dbSetMock.Object; 
    } 
} 

Si je l'exécute, le test échoue, car la méthode getAll() retaille null. Il semble que la propriété 'Entities' n'a pas été correctement initialisée par la méthode Set().

Lorsque je définis un point d'arrêt dans le constructeur de référentiel et que j'examine la propriété Entities, sous 'Expression> Value> Result View', les trois entrées apparaissent. Sous la première vue des résultats, il y a un message "Enumeration yielded no results" et deux lignes avec? dedans (Visual Studio 2017).

Comment puis-je corriger les entités dans le référentiel correctement? Qu'est-ce que je fais mal?

Répondre

0

La documentation EF couvre ce sujet.

  1. Utilisez IDbSet<T> dans votre contexte. Créez une fausse implémentation de IDbSet<T> pour vos tests.

Voir https://msdn.microsoft.com/en-gb/data/dn314431.

Notez qu'il existe également une page sur l'utilisation des frameworks de simulation, mais je n'ai jamais fait cela: https://msdn.microsoft.com/en-gb/data/dn314429.

Notez également, si vous utilisez EF Core (aka EF7), il y a un fournisseur de mémoire qui évite d'avoir besoin du double.

2

J'ai recréé le test en me basant exactement sur l'exemple fourni dans la question d'origine et je n'ai pas pu reproduire le problème null. Le simulacre a retourné une collection peuplée comme elle était configurée pour le faire.

Un problème est survenu cependant lorsque l'on compare les deux collections,

Assert.AreEqual(repository.GetAll(), allTestData); 

ils n'ont pas été considérés comme égaux. Attendu, car le ToList créerait une nouvelle liste qui serait évidemment une référence différente à la liste originale utilisée comme source de données pour le faux.

Comparez les deux collections en utilisant CollectionAssert.AreEquivalent à la place

[TestMethod] 
public void Setup_Test() { 
    var actual = repository.GetAll(); 
    CollectionAssert.AreEquivalent(allTestData, actual); 
} 

et le test passe.