2010-02-11 10 views
30

Ich erstelle ein Repository, das IQueryable exponiert. Was ist der beste Weg, dies für meine Unit-Tests zu verspotten?Wie spot ich IQueryable <T>

Da verwende ich RhinoMocks für den Rest meines Mock-Objekte, versuchte ich folgendes zu tun:

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

Dies funktioniert nicht, obwohl so habe ich versucht, dies zu tun:

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

Gibt es eine bessere Möglichkeit, dies zu tun, oder haben andere spöttische Frameworks Unterstützung für IQueryable in?

Meine Repository-Schnittstelle sieht wie folgt aus:

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); 
} 

Hier ist die Methode, die ich testen wollen:

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(); 
} 

Dann ist hier der Test, wie ich es haben, dass gerade jetzt testen 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); 
} 

ist der Code von meinem AzureBlog Projekt übernommen.

+0

Können Sie Ihren Test einfügen? – Grzenio

Antwort

8

ich in der Regel genau das tun, was Sie in Ihrem Test am Ende tun. Beim Schreiben meiner Tests gehe ich davon aus, dass die .Net-Bibliotheksklassen korrekt funktionieren und keine Fehler enthalten, sodass ich sie in den Tests verwenden kann. Wenn ich eine Testliste, eine Sammlung, ein abfragbares Verzeichnis, ein Wörterbuch usw. benötige, erstelle ich einfach das echte Ding und bevölke mich mit Testdaten. Es macht die Tests viel lesbarer und schneller zu schreiben, und um ehrlich zu sein, besteht das Risiko nicht.

3

Wenn Sie Ihr Repository verspotten möchten, werden Sie IQQueryable nicht verspotten. Spotten Sie stattdessen die Methoden Ihres Repositorys aus, um feste, bekannte Werte (wie in Ihrem zweiten Beispiel) zurückzugeben, mit denen Sie Ihre Komponententests ausführen können.

+0

Ich hatte diese Route gestartet und dann eine zusätzliche Ebene eines bestimmten Repository über ein generisches Repository erstellt. Dies führte zu meinem Domain Service -> Domain Repository -> Generisches Repository. Wenn ich von Domain Service -> Generic Repository gehen und trotzdem testbar sein kann, ohne dass Implementierungsdetails in den Domain Service eindringen, wäre ich viel glücklicher, da weniger Code gewartet und getestet werden muss. –

+0

Ich sehe was du sagst. Aber wenn Ihre Frage durch das Schreiben von Komponententests für Ihren DomainService entstand, dann sollten Sie sich über das DomainRepository lustig machen und sich nicht um das generische Repository (für jetzt) ​​sorgen. Das Testen von Einheiten des DomainService wird am besten durch Verspotten der Abhängigkeiten erreicht. Soweit der DomainService geht, sollte es nicht wichtig sein, wie DomainRepository implementiert wird (d. H. Von einer Basisklasse erbt). Hoffe das hilft! – PatrickSteele

0

Ich bin mir nicht sicher, ob dies dir helfen wird ... aber ich habe etwas getan, worüber du sprichst. In meinem Szenario hatte ich eine Datenkontextklasse, die das Repository verwendet.

Ich begann mit dem Erstellen einer Schnittstelle (IRepository), die die IQueryable-Methode enthalten. Dann habe ich zwei Klassen erstellt, die diese Schnittstelle implementieren. Eine Klasse verwendet ein ORM für die Datenmanipulation (DbEntityRepository) und eine andere Klasse verwendet eine Klasseneigenschaft (MemoryRepository). Die Datenkontextklasse hatte einen Konstruktor, der das IRepository benötigte. Auf diese Weise könnte ich das MemoryRepository zum Testen des Datenkontexts verwenden und das DbEntityRepository für die Anwendung verwenden.

Wenn Sie interessiert sind ... Sie den Code auf Codeplex finden: IQToolkitContrib

2

Ich weiß, das ist eine alte Frage, aber nur meine 2 Cent hinzufügen möchten.

Ich hatte das gleiche Problem mit den Repositories, die mit SharpLite generiert wurden, welches ein ASP.NET MVC Framework ist, das ich von Zeit zu Zeit verwende. Nach einiger Zeit habe ich eine Lösung gefunden, das einzige Problem ist die Verwendung von Moq und nicht Rhino Mocks, aber möglicherweise können Sie einen Weg finden, es anzupassen. Ich machte eine blog post here auf wie es geht.

Es erstellt im Grunde eine Liste, die IQueryable implementiert und als gefälschten Datenhintergrund verwendet. Ich hoffe, ich kann helfen!