2015-07-10 11 views
20

Sto provando a configurare un DbSet fittizio a scopo di test. Ho usato il tutorial qui, http://www.loganfranken.com/blog/517/mocking-dbset-queries-in-ef6/ e leggermente modificato, quindi chiamare GetEnumerator restituisce un nuovo enumeratore ogni volta (un altro problema che stavo avendo). Tuttavia, ho difficoltà ad aggiungere elementi a DbSet.Come aggiungere un elemento a un DbSet fittizio (usando Moq)

L'output è preCount = 3 postCount = 3. Tuttavia, mi aspetto che sia precount = 3 postCount = 4. Qualsiasi aiuto è molto apprezzato.

static void Main(string[] args) 
    { 
     Debug.WriteLine("hello debug"); 

     List<string> stringList = new List<string> 
     { 
      "a", "b", "c" 
     }; 

     DbSet<string> myDbSet = GetQueryableMockDbSet(stringList); 
     int preCount = myDbSet.Count(); 
     myDbSet.Add("d"); 
     int postCount = myDbSet.Count(); 
     Debug.WriteLine("preCount = " + preCount + " postCount = " + postCount); 
    } 

    private static DbSet<T> GetQueryableMockDbSet<T>(List<T> sourceList) where T : class 
    { 
     var queryable = sourceList.AsQueryable(); 

     var dbSet = new Mock<DbSet<T>>(); 
     dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider); 
     dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression); 
     dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType); 
     dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator()); 

     return dbSet.Object; 
    } 
+0

metodo molto bello per incapsulare la creazione del dbSet. Qualche possibilità che hai aggiornato per supportare query asincrone? –

+0

Questo, almeno per il momento con .net core 1.0, risponderà al problema asincrono: [Come prendere in giro un repository asincrono con Entity Framework Core] (https://stackoverflow.com/questions/40476233/how-to-mock -an-async-repository-with-entity-framework-core) –

risposta

53

myDbSet non è reale implementazione di DbSet ma un mock che significa che è falso e ha bisogno di essere configurato per tutti i metodi necessari. Lo Add non è un'eccezione quindi è necessario impostarlo per fare ciò che è necessario altrimenti non fa nulla.

Aggiungi qualcosa come la seguente e quando viene chiamato il numero myDbSet.Add("d");, la "d" viene aggiunta all'elenco e può essere restituita in seguito.

dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => sourceList.Add(s)); 

completo del codice

private static DbSet<T> GetQueryableMockDbSet<T>(List<T> sourceList) where T : class 
{ 
    var queryable = sourceList.AsQueryable(); 

    var dbSet = new Mock<DbSet<T>>(); 
    dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider); 
    dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression); 
    dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType); 
    dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator()); 
    dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>((s) => sourceList.Add(s)); 

    return dbSet.Object; 
} 

uscita

hello debug 
preCount = 3 postCount = 4 
+0

Il problema è che quando aggiungi qualcosa al database dovrai impostare manualmente le proprietà di navigazione, mentre questo mocking salverà l'oggetto così com'è. Mi chiedo se c'è un modo per emulare il comportamento di EF su questo. – tocqueville

+2

Il punto di derisione EF è perché non si desidera portare un database nei test. È meglio avere test veloci e compartimentati che testano solo una specifica API. Un'altra opzione è un https://msdn.microsoft.com/en-us/data/dn314431.aspx "in-memory double", tuttavia, i duplicati in-memory e il mocking sono essenzialmente la stessa cosa. – andrew

+0

Qualche possibilità che hai aggiornato per supportare query asincrone? –