32

Perché voglio testare il mio codice unitario ho implementato il pattern di repository nella mia applicazione MVC4. Sono riuscito a creare un'interfaccia di contesto, un finto contesto e utilizzare un'implementazione fittizia di System.Data.Entity.DbSet seguendo il codice this.Come simulare il metodo DbContext.Entry in Entity Framework con pattern di repository

Purtroppo, proprio come due poster prima di me (here e here), non riesco a prendere in giro il DbContext.Entry method. Io uso questo metodo per l'aggiornamento voci del database nel mio codice come segue:

DbContext.Entry(order).State = EntityState.Modified; 

non ho trovato una soluzione a questo problema, solo le persone che dicono cose come:

"e qual è il punto di unità testare questo codice? Si falsi il metodo Trova , quindi si falsi DbEntityEntry e non ci sarà alcuna logica reale per il test ".

o per

leggere this e tutte le questioni legate prima di continuare. (...) Se vuoi testare i tuoi repository, crea test di integrazione parlando con il vero database.

Questo è tutto buono e buono, ma ancora nessuna risposta alla domanda. Ho letto la critica e desidero ancora questo metodo di inserimento, in modo da poter utilizzare un contesto falso e utilizzare oggetti fittizi nel mio test di unità. Naturalmente userò anche i test di integrazione, ma non sono così veloci come alcuni test rapidi delle unità.

L'errore che ricevo quando provo alcune implementazioni è che Error 2 'Project.Models.Order' does not contain a definition for 'State' and no extension method 'State' accepting a first argument of type '[whatever return type I use]' could be found (are you missing a using directive or an assembly reference?)

Spero che qualcuno possa aiutarmi a fare un metodo DbContext.Entry falso.

+0

Utilizzare un motivo repository in cui gli archivi implementano un'interfaccia generica accoppiato all'unità di modello di lavoro. In questo modo, hai solo bisogno di deridere o fingere l'unità di lavoro. – Maess

+0

Ho visto il primo dei due post SO a cui ti sei collegato e c'è una risposta che è stata ignorata. Ma potrebbe essere completamente irrilevante per il tuo problema. Si prega di inviare * il * codice in modo da poter fornire una buona risposta. –

+0

@KeithPayne c'è una risposta? –

risposta

30

ha trovato la risposta here "aggiungendo ulteriore livello di riferimento indiretto" otteniamo:

public void SetModified(object entity) 
{ 
    Entry(entity).State = EntityState.Modified; 
} 

e usiamo DbContext.SetModified(entity) nel nostro controller.

2

Un esempio di come implementare repository basati su interfaccia e unità di lavoro per ottenere ciò che stai cercando:

public interface IRepository<T> 
    { 
     T FindSingle(Expression<Func<T, Boolean>> predicate, params Expression<Func<T, object>>[] includeExpressions); 
     void ProxyGenerationOn(); 
     void ProxyGenerationOff(); 
     void Detach(T entity); 
     void Add(T newEntity); 
     void Modify(T entity); 
     void Attach(T entity); 
     void Remove(T entity); 
     void SetCurrentValues(T modifiedEntity, T origEntity); 
     T GetById(int id); 
     T GetById(int id, bool sealOverride); 
     IQueryable<T> GetAll(); 
     IQueryable<T> GetAll(bool sealOverride); 
     IQueryable<T> GetAll(string[] EagerLoadPaths); 
     IQueryable<T> Find(Expression<Func<T, Boolean>> predicate); 
    } 



public interface IUnitOfWork : IDisposable 
    { 
     //repository implementations go here 
     bool SaveChanges() 
    } 

Si noti come il contesto è completamente astratta via. Hai solo bisogno di preoccuparti di questo nelle implementazioni concrete.

+3

Per approfondire: OP dovrebbe, nella sua implementazione 'Modify()', chiamare 'DbContext.Entry (entity) .State = EntityState.Modified;'. Quindi, quando si prova il codice usando il repository, si deve solo prendere in giro il repository e _verificare che 'repository.Modify()' è stato chiamato_. – CodeCaster

+0

@CodeCaster che è una bella spiegazione. –

+0

@Maess Sono abbastanza nuovo in questo, sono unità di lavoro solo chiamate di metodo che vengono sottratte? Ad esempio, invece di usare 'DbContext.SaveChanges' direttamente faccio' repository.SaveChanges' e il contesto è nel repository che ho istanziato? –

3

Per aggirare questo ho aggiunto un overload di metodo e aggiunto un attributo obsoleto per vedere dove veniva chiamato il metodo originale.

public virtual void Entry<TEntity>(TEntity entity, Action<DbEntityEntry<TEntity>> action) where TEntity : class 
    { 
     action(base.Entry(entity)); 
    } 

    [Obsolete("Use overload for unit tests.")] 
    public new DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class 
    { 
     return base.Entry(entity); 

     /** or **/ 

     throw new ApplicationException("Use overload for unit tests."); 
    } 

quindi si può DbContext.Entry(order, ent => ent.State = EntityState.Modified;

Problemi correlati