2010-02-11 14 views
30

Sto creando un repository che espone IQueryable. Qual è il modo migliore per deriderlo per i miei test unitari?Come faccio a fingere IQueryable <T>

Dal momento che sto usando RhinoMocks per il resto dei miei oggetti mock, ho cercato di fare quanto segue:

IQueryable<MyObject> QueryObject = 
    MockRepository.GenerateStub<IQueryable<MyObject>>(); 

Questo non funziona anche se così ho provato a fare questo:

IQueryable<MyObject> QueryObject = 
    (new List<MyObject> { new MyObject() }).AsQueryable(); 

C'è un modo migliore per farlo o avere altri framework di simulazione che supportano IQueryable in?

mia interfaccia repository si presenta così:

public interface IRepository<T> where T : TableServiceEntity 
{ 
    IQueryable<T> Table { get; } 
    void Attach(T existingItem); 
    void Delete(T itemToDelete); 
    void Insert(T newItem); 
    T Load(string partitionKey, string rowKey); 
    IEnumerable<T> Load(string partitionKey); 
    IEnumerable<T> Query(IQueryable<T> query); 
    IEnumerable<T> Last(int count); 
    T Last(); 
    void Update(T item); 
} 

Ecco il metodo che voglio prova:

public Post LoadPost(int year, int month, int day, string slug) 
{ 
    var query = from p in _blogRepository.Table 
       where 
        p.PartitionKey == Key.Partition(year, month, day) 
        && p.Slug == slug 
       select p; 

    var posts = _blogRepository.Query(query.Take(1)); 

    return posts.First(); 
} 

allora ecco la prova come ce l'ho in questo momento che metterà alla prova LoadPost .

[Fact] 
public void LoadWillRetrieveByPartitionKeyAndRowKeyWhenUsingUriFormat() 
{ 
    Repository 
     .Stub(x => x.Query(Arg<IQueryable<Post>>.Is.Anything)) 
     .Return(new List<Post> {_post}); 

    var result = Service.LoadPost(
          _post.Year(), 
          _post.Month(), 
          _post.Day(), 
          _post.Slug); 

    Assert.NotNull(result); 
} 

Il codice è tratto dal mio progetto AzureBlog.

+0

Potresti incollare il test? – Grzenio

risposta

8

solito faccio esattamente quello che ha finito per fare nel test. Quando scrivo i miei test, suppongo che le classi della libreria .Net funzionino correttamente e non contengano bug, quindi posso usarli nei test. Quando ho bisogno di una lista di test, raccolta, interrogabile, dizionario, ecc. Creo solo la cosa reale e popola con i dati di test. Rende i test molto più leggibili e veloci da scrivere, e ad essere onesti il ​​rischio è inesistente.

3

Se si vuole prendere in giro il proprio repository, non si sta prendendo in giro IQueryable. Invece, prendi in giro i metodi del tuo repository per restituire valori noti e fissi (come il tuo secondo esempio) che possono essere usati per eseguire i tuoi test unitari.

+0

Avevo avviato questa rotta e poi ho finito con la creazione di un ulteriore livello di un repository specifico su un repository generico. Ciò ha comportato il mio servizio di dominio -> Domain Repository -> Repository generico. Se sono in grado di passare dal servizio di dominio -> Repository generico ed essere ancora testabile senza dettagli di implementazione che sfuggono al servizio di dominio, sarei molto più felice in quanto è meno codice che deve essere mantenuto e testato. –

+0

Vedo quello che stai dicendo. Ma se la tua domanda nasce dalla scrittura di unit test per il tuo DomainService, allora penso che dovresti prendere in giro il DomainRepository e non preoccuparti del Repository generico (per ora). L'unità che esegue il test di DomainService può essere meglio realizzata prendendo in giro le sue dipendenze. Per quanto riguarda il DomainService, non dovrebbe importare come è implementato DomainRepository (cioè ereditare da una classe base). Spero che questo ti aiuti! – PatrickSteele

0

Non sono sicuro se questo ti aiuterà ... ma ho fatto qualcosa di simile a quello di cui stai parlando. Nel mio scenario, avevo una classe di contesto dati che utilizzava il repository.

Ho iniziato creando un'interfaccia (IRepository) che includeva il metodo IQueryable. Quindi ho creato due classi che implementano questa interfaccia. Una classe utilizza un ORM per la manipolazione dei dati (DbEntityRepository) e un'altra classe utilizza una proprietà di classe (MemoryRepository). La classe di contesto dei dati aveva un costruttore che richiedeva l'IRepository. Facendo questo potrei usare il MemoryRepository per quando testare il contesto dei dati e potrei usare DbEntityRepository per l'applicazione.

Se siete interessati ... si può trovare il codice su CodePlex: IQToolkitContrib

2

So che questa è una vecchia domanda, ma voglio solo aggiungere i miei 2 centesimi.

Ho avuto lo stesso problema con i repository generati con SharpLite, che è un framework ASP .NET MVC che uso di volta in volta. Dopo un po 'di tempo, ho trovato una soluzione, l'unico problema è che utilizza Moq e non Rhino Mocks, ma forse puoi trovare un modo per adattarlo. Ho fatto un blog post here su come farlo.

In pratica sta creando un elenco che implementa IQueryable e lo utilizza come sfondo di dati falsi. Spero di poterti aiutare!

Problemi correlati