2017-09-04 5 views
2

J'utilise .NET Core 2.0 et le pilote .NET Core MongoDB.Tests unitaires avec IMongoQueryable

J'ai créé un dépôt comme ceci:

public interface IRepository<T> 
{ 
    IMongoQueryable<T> Get() 
} 

Je l'ai fait pour donner de la flexibilité à quiconque utilise pour pouvoir faire LINQ un peu comme ils le feraient en utilisant EF. Le problème est quand il s'agit de tests unitaires et j'essaie de créer une base de données en mémoire afin que je puisse vérifier les états avant et après l'opération.

Quelques trucs que j'ai essayé:

public class InMemoryRepository : IRepository<ConcreteType> 
{ 
    private HashSet<ConcreteType> _data = new HashSet<ConcreteType>(); 

    public IMongoQueryable<ConcreteType> Get() 
    { 
     return (IMongoQueryable<ConcreteType>)_data.AsQueryable(); 
    } 
} 

L'affaire ne fonctionne pas comme l'interface pour IMongoQueryable est:

public interface IMongoQueryable<T> : IMongoQueryable, IQueryable, IEnumerable, IQueryable<T>, IEnumerable<T>, IAsyncCursorSource<T> 

Un autre go:

public class InMemoryRepository : IRepository<ConcreteType> 
{ 
    private HashSet<ConcreteType> _data = new HashSet<ConcreteType>(); 

    public InMemoryRepository() 
    { 
     _mongoQueryableMock = new Mock<IMongoQueryable<ConcreteType>>(); 
     _mongoQueryableMock.Setup(m => m.AsQueryable()).Returns(_data.AsQueryable); 
    } 

    public IMongoQueryable<ConcreteType> Get() 
    { 
     return _mongoQueryableMock.Object; 
    } 
} 

Cela ne travailler comme IMongoQueryable.AsQueryable() est une méthode d'extension et je ne peux pas mock/setup cela.

+1

Il est toujours difficile et dangereux de se moquer de l'interface IQueryable, car vous ne pouvez pas imiter correctement le comportement de l'implémentation. Par conséquent, vous pourriez passer mais cela ne fonctionnera pas contre une véritable instance de MongoDb. Le rôle du référentiel est d'abstraire la technologie d'accès aux données de la logique métier de votre application. Si votre référentiel expose des interfaces spécifiques à MongoDb à votre couche de gestion, vous avez alors une abstraction qui fuit. Vous risquez de lier votre logique métier à une technologie d'accès aux données spécifique. –

Répondre

1

Configurez le modèle pour pouvoir traiter les appels IQueryable.

public class InMemoryRepository : IRepository<ConcreteType> { 
    private HashSet<ConcreteType> _data = new HashSet<ConcreteType>(); 
    private Mock<IMongoQueryable<ConcreteType>> _mongoQueryableMock; 

    public ReviseMeasureRepository() {  
     var queryableList = _data.AsQueryable(); 

     _mongoQueryableMock = new Mock<IMongoQueryable<ConcreteType>>(); 
     _mongoQueryableMock.As<IQueryable<ConcreteType>>().Setup(x => x.Provider).Returns(queryableList.Provider); 
     _mongoQueryableMock.As<IQueryable<ConcreteType>>().Setup(x => x.Expression).Returns(queryableList.Expression); 
     _mongoQueryableMock.As<IQueryable<ConcreteType>>().Setup(x => x.ElementType).Returns(queryableList.ElementType); 
     _mongoQueryableMock.As<IQueryable<ConcreteType>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator());  
    } 

    public IMongoQueryable<ConcreteType> Get() { 
     return _mongoQueryableMock.Object; 
    } 

    //... 
} 

Avec cela à la façon dont je pense que la conception du dépôt est qui fuit et directement les couples votre code à des dépendances externes. Envisagez d'examiner la conception de l'abstraction du référentiel.

+0

Je ne sais pas si c'est hors de la portée de cette question, mais avez-vous des idées là-dessus? Si je voulais utiliser say '.Take()' et '.Offset()', je devrais écrire des méthodes spécifiques pour ceux-ci. J'ai essayé de faire en sorte que le référentiel ne soit pas couplé et réussi avec les autres méthodes CRUD mais je n'ai pas trouvé de moyen de rendre la collection. Je ne veux évidemment pas retourner le tout dans la base de données et les laisser filtrer ce qu'ils veulent en mémoire. –

+1

@KevinLee, C'est une toute nouvelle question. C'est aussi le problème de l'abstraction pour l'amour de l'abstraction. Résumé les comportements souhaités. Rendez donc votre API plus ciblée sur ce que vous voulez exposer. L'exposition de IQueryable a des fuites. '.Take()' et '.Offset()' sont des problèmes d'implémentation qui devraient être encapsulés par votre implémentation du comportement désiré. – Nkosi