2013-04-03 7 views
11

Attualmente sto cercando di unità di prova un repository che ho fatto attraverso Entity Framework:Come testare unitamente un pattern di repository che utilizza Entity Framework?

Quello che voglio che accada è che prova il repository, senza in realtà l'invio/la connessione al database vero e proprio, voglio questo senza usare alcun beffardo struttura.

Attualmente il mio test sta inviando i dati al database, quello che voglio succedere è testare i metodi add/remove etc. senza inviare i dati effettivi al database poiché è solo per il test.

Ecco il 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; 
     } 
    } 
} 

ecco il codice corrente per la prova di unità:

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

voglio usare spessori/stub/falsi al fine di rendere il test.

+0

Qual è la domanda? –

+1

Se tutto ciò che i repository stanno facendo è una linea di codice che sta effettuando una chiamata a EF, allora non è necessario eseguire alcuna verifica unitaria su di essa. Anche lo zio Bob è d'accordo: http://blog.8thlight.com/uncle-bob/2013/03/06/ThePragmaticsOfTDD.html – IronMan84

+0

+ 1 a @ IronMan84 - non si preoccupa di testare alcun framework, altrimenti potresti potenzialmente trovarti a testare il codice che non puoi sistemare. –

risposta

14

Il repository Entity Framework è un'implementazione concreta dell'interfaccia del repository. Perché è concreto, non puoi astrarre e testare senza il database - il punto centrale di questa implementazione concreta è scrivere i dati nel database!

Ciò significa che testare i repository EF dovrebbe piuttosto mirare a verificare che gli archivi scrivano sul database effettivo - nella fase act del test si invocano i metodi del repository e nella fase assert si utilizza qualsiasi altro modo per ottenere i dati dal database (ado.net forse?) per verificare se il repository fa il suo lavoro.

Ancora un altro, cosa non correlato è che si può avere un'altra implementazione del repository che utilizza un archivio di dati in memoria e l'iniezione di tale repository in-memory ad altri servizi vi permette di testare questi servizi wihout scrittura in un database fisico. Potresti persino prendere in giro un repository iniettato ad altri servizi solo per eseguire alcuni test comportamentali, cioè testare se i tuoi servizi usano correttamente i tuoi repository.

+4

+1 Troppe persone cercano di prendere in giro qualcosa che non può essere deriso. Ho raccolto alcune prove [qui] (http://stackoverflow.com/a/13352779/861716). –

+0

@GertArnold: prove notevoli. –

+0

Se ho capito, stai dicendo che dovremmo creare un'altra implementazione di accesso ai dati (usando ado.net) per verificare che l'EF funzioni. Questo non aggiunge un sovraccarico? – betitall

5

È possibile sostituire la connessione al database con DB in memoria, ad esempio Effort. Quindi puoi testare la logica del repository. Più dettagli possono essere trovati here

+3

Penso che questo dovrebbe essere un commento e non è una risposta. –