2013-04-03 5 views
11

Ich bin gerade dabei, ein Repository durch Entity Framework Einheit testen zu testen:Wie Unit-Test ein Repository-Muster, das Entity Framework verwendet?

Was ich möchte ist, dass das Repository testen, ohne tatsächlich zu senden/verbinden mit der tatsächlichen Datenbank, möchte ich dies ohne zu spotten Rahmen.

Momentan sendet mein Test die Daten an die Datenbank, was ich tun möchte, ist die Add/Remove etc. Methoden testen, ohne die eigentlichen Daten an die Datenbank zu senden, da es nur zum Testen ist. Hier

ist das Repository:

namespace AbstractFactory.Repository 
{ 
    using System.Collections.Generic; 
    using System.Data.Entity; 
    using System.Linq; 

    /// <summary> 
    /// This class serves as the structure of the Author repository using a database 
    /// </summary> 
    public class DbAuthorRepository : IRepository<AuthorEntity> 
    { 

     private AbstractFactoryPatternEntities context; 

     public DbAuthorRepository(AbstractFactoryPatternEntities context) 
     { 
      this.context = context; 
     } 

     /// <summary> 
     /// Adds the specified author. 
     /// </summary> 
     /// <param name="author">The author.</param> 
     public void Add(AuthorEntity author) 
     { 
      context.AuthorEntities.Add(author); 
     } 

     /// <summary> 
     /// Removes the specified author. 
     /// </summary> 
     /// <param name="author">The author.</param> 
     public void Remove(AuthorEntity author) 
     { 
      this.context.AuthorEntities.Remove(author); 
     } 

     /// <summary> 
     /// Saves this instance. 
     /// </summary> 
     public void Save() 
     { 
      this.context.SaveChanges(); 
     } 

     /// <summary> 
     /// Gets all. 
     /// </summary> 
     /// <returns>returns a list of all the authors</returns> 
     public IEnumerable<AuthorEntity> GetAll() 
     { 
      List<AuthorEntity> result = this.context.AuthorEntities.Include(a => a.Books).ToList(); 

      return result; 
     } 

     /// <summary> 
     /// Gets the author by id. 
     /// </summary> 
     /// <param name="id">The id.</param> 
     /// <returns>returns an entity</returns> 
     public AuthorEntity GetById(int id) 
     { 
      AuthorEntity result = this.context.AuthorEntities.Single(a => a.AuthorId == id); 

      return result; 
     } 
    } 
} 

Hier ist der aktuelle Code für das Gerät zu testen:

[TestMethod] 
     public void Add_MethodIsCalled_EntityCountIsIncrementedByOne() 
     { 
      using (ShimsContext.Create()) 
      { 
       ShimAbstractFactoryPatternEntities context = new ShimAbstractFactoryPatternEntities(new AbstractFactoryPatternEntities()); 
       DbAuthorRepository repository = new DbAuthorRepository(context); 
       repository.Add(new AuthorEntity { FirstName = "Test", LastName = "testing=" }); 
       var actual = repository.GetAll().Count(); 
       repository.Save(); 
       var expected = repository.GetAll().Count(); 
       Assert.AreNotEqual(actual, expected); 
      } 

      //AbstractFactoryPatternEntities context = new AbstractFactoryPatternEntities(); 
      //DbAuthorRepository repository = new DbAuthorRepository(context); 
      //var actual = repository.GetAll().Count(); 
      //repository.Add(new AuthorEntity { FirstName = "Testing", LastName = "MyTest" }); 
      //repository.Save(); 
      //var expected = repository.GetAll().Count(); 
      //Assert.AreNotEqual(actual, expected); 
     } 

     [TestMethod] 
     public void Remove_MethodIsCalled_EntityCountRemainsTheSame() 
     { 
      AbstractFactoryPatternEntities context = new AbstractFactoryPatternEntities(); 
      DbAuthorRepository repository = new DbAuthorRepository(context); 
      AuthorEntity newAuthor = new AuthorEntity { FirstName = "Testing", LastName = "MyTest" }; 
      repository.Add(newAuthor); 
      repository.Save(); 
      var actual = repository.GetAll().Count(); 
      Console.WriteLine(actual); 
      repository.Remove(newAuthor); 
      var expected = repository.GetAll().Count(); 
      Console.WriteLine(expected); 
      Assert.AreEqual(actual, expected); 
     } 

     [TestMethod] 
     public void Get_MethodIsCalled_CorrectAuthorIsRetrieved() 
     { 
      AbstractFactoryPatternEntities context = new AbstractFactoryPatternEntities(); 
      DbAuthorRepository repository = new DbAuthorRepository(context); 
      int target = 4; 
      AuthorEntity author = repository.GetById(target); 
      Assert.AreEqual(target, author.AuthorId); 
     } 

ich verwenden möchte Unterlegscheiben/Stub/Fakes, um den Test zu machen.

+0

Was ist die Frage? –

+1

Wenn all Ihre Repositorys nur eine Codezeile sind, die einen Aufruf an EF sendet, müssen Sie keinerlei Form von Komponententests ausführen. Selbst Onkel Bob stimmt zu: http://blog.8thlight.com/uncle-bob/2013/03/06/ThePragmaticsOfTDD.html – IronMan84

+0

+ 1 bis @ IronMan84 - nicht stören Testen von Framework, sonst könnten Sie möglicherweise finden, dass Sie Code testen Sie können nicht reparieren. –

Antwort

14

Das Entity Framework-Repository ist eine konkrete Implementierung Ihrer Repository-Schnittstelle. Weil es konkret ist, kann man es nicht abstrahieren und ohne die Datenbank testen - der springende Punkt dieser konkreten Implementierung ist, die Daten in die Datenbank zu schreiben! Dies bedeutet, dass das Testen von EF-Repositories eher darauf abzielen sollte, zu überprüfen, dass Repositories in die eigentliche Datenbank schreiben - in der Vorgangsphase des Tests rufen Sie Repository-Methoden auf und in der Assert-Phase verwenden Sie andere Methoden, um die Daten aus der Datenbank abzurufen (ado.net vielleicht?), um zu überprüfen, ob das Repository seine Arbeit macht. Ein weiteres, nicht verwandtes Ding ist, dass Sie eine andere Implementierung des Repositorys haben können, die einen In-Memory-Datenspeicher verwendet und dieses In-Memory-Repository in andere Services injiziert, um diese Services zu testen, ohne in eine physische Datenbank zu schreiben. Sie könnten sogar ein Repository vortäuschen, das anderen Diensten injiziert wird, nur um einige Verhaltenstests durchzuführen, d. H. Zu testen, ob Ihre Dienste Ihre Repositories korrekt verwenden.

+4

+1 Zu viele Leute versuchen etwas zu verspotten, das nicht verspottet werden kann. Ich habe einige Beweise gesammelt [http://stackoverflow.com/a/13352779/861716]. –

+0

@GertArnold: beeindruckende Beweise. –

+0

Wenn ich verstehe, sagen Sie, dass wir eine andere Datenzugriffsimplementierung (mit ado.net) erstellen sollten, um zu überprüfen, ob EF funktioniert. Ist das nicht viel Aufwand? – betitall

5

Sie können die Verbindung zu Ihrer Datenbank durch In-Memory-DB ersetzen, z. B. Aufwand. Dann können Sie Ihre Repository-Logik testen. In mehr Details finden Sie here

+3

Ich denke, das sollte ein Kommentar sein und es ist keine Antwort. –