2014-05-04 15 views
15

Sto cercando di prendere in giro DbContext e DbSet. Questo funziona per i miei precedenti test di unità, ma il problema si verifica mentre il mio codice stava chiamando il metodo ToList su DbSet la seconda volta.DbSet mock, nessun risultato durante la chiamata ToList secondly

First dbSet.ToList() restituisce risultati di mocking. Secondo uno restituisce 0 elementi;

 var queryableData = new List<string>{ "a", "b", "c" }.AsQueryable(); 

     var mockDbSet = new Mock<DbSet<string>>(); 
     var q = mockDbSet.As<IQueryable<string>>(); 
     q.Setup(m => m.Provider).Returns(queryableData.Provider); 
     q.Setup(m => m.Expression).Returns(queryableData.Expression); 
     q.Setup(m => m.ElementType).Returns(queryableData.ElementType); 
     q.Setup(m => m.GetEnumerator()).Returns(queryableData.GetEnumerator()); 

     DbSet<string> dbset = mockDbSet.Object; 
     IQueryable<string> query = dbset; 

     //RESULTS: abc 
     var a1 = dbset.ToList(); 
     foreach (var a in a1) 
      Console.Write(a); 

     //NO RESULTS 
     var a2 = dbset.ToList(); 
     foreach (var a in a2) 
      Console.Write(a); 

risposta

36

di restituire il molto stessa istanza enumeratore su ogni chiamata a GetEnumerator. Quando viene enumerato una volta, l'EF non chiama il suo metodo Reset, ma richiede un nuovo enumeratore.

Ma si ritorna quello che ha appena prodotto tutti gli elementi e non produce più.

Invece, restituisce una funzione che restituisce l'enumeratore, che restituirà un nuovo enumeratore ogni volta che lo chiedi.

q.Setup(m => m.GetEnumerator()).Returns(() => queryableData.GetEnumerator()); 
+0

Questo mi stava uccidendo. Grande cattura. – RMD

+0

Questo è stato un orso per me per un paio di mesi. Finalmente sono entrato in una situazione in cui non potevo evitarlo. Questo ha aiutato così tanto! –

+0

Questo ha reso la mia vita molto migliore. Grazie. –

0

Se si inserisce una clausola "Where" prima della chiamata .ToList(), i dati devono rimanere presenti.

var a1 = dbset.Where(m => m != null).ToList(); 

var a2 = dbset.Where(m => m != null).ToList(); 
2

Volevo solo aggiungere alla risposta di Wiktor Zychla la mia piccola parte. Se qualcuno è alla ricerca per la versione asincrona di questo finto (venendo da questo tutorial: http://msdn.microsoft.com/en-us/data/dn314429.aspx#async), allora questo è il mio modifica TestDbAsyncEnumerator<T> classe:

internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T> 
{ 
    private readonly IEnumerator<T> _inner; 

    public TestDbAsyncEnumerator(IEnumerator<T> inner) 
    { 
     _inner = inner; 
    } 

    public TestDbAsyncEnumerator(Func<IEnumerator<T>> valueFunction) 
    { 
     _inner = valueFunction(); 
    } 

    public void Dispose() 
    { 
     _inner.Dispose(); 
    } 

    public Task<bool> MoveNextAsync(CancellationToken cancellationToken) 
    { 
     return Task.FromResult(_inner.MoveNext()); 
    } 

    public T Current 
    { 
     get { return _inner.Current; } 
    } 

    object IDbAsyncEnumerator.Current 
    { 
     get { return Current; } 
    } 
} 

Poi, come Wiktor suggerito è necessario configurare con delegato quindi in caso di asincrona sarebbe così:

mockSet.As<IDbAsyncEnumerable<Blog>>() 
      .Setup(m => m.GetAsyncEnumerator()) 
      .Returns(new TestDbAsyncEnumerator<Blog>(() => data.GetEnumerator())); 

Se qualcuno vuole fonte per che allora qui si va: https://github.com/kelostrada/EntityFrameworkWithMock.Test

+0

Il codice nel repository GitHub non corrisponde a quello che hai nello stackoverflow? Non funziona nel mio caso in entrambi i casi. – Riga

+0

cosa non funziona per te?Non ho guardato questo codice per più di 2 anni, potrebbe non funzionare a causa di alcuni aggiornamenti del pacchetto e cose del genere. Non viene compilato? Inoltre ho scoperto che provare a deridere DbSets è stato come il compito più arduo che abbia mai affrontato ... non l'avrei mai più provato. Basta impostare un nuovo database per i test e impostare una transazione su ciascun test: una soluzione molto più affidabile e facile da usare. (forse solo un po 'più lento) –

+0

il mio commento è più sul codice qui e nel repository collegato non corrisponde. Le build del codice, ma non risolvono problemi simili, sono descritte qui: http://stackoverflow.com/questions/41899177/mock-entity-framework-long-linq-query/41900708#41900708. Capisci ora che il Dashet beffardo è un modo molto difficile e forse non il migliore, pensava che EF fosse fatto per essere testabile, ma forse non lo è. Troppo tardi ora per cambiare le cose nel progetto su cui lavorare. Grazie. – Riga

2

non posso commentare il post di Wiktor come non ho abbastanza reputazione, ma vorrei piace aggiungere un piccolo extra alla risposta di Wiktor.

Il codice

mockSet.Setup((m => m.GetEnumerator()).Returns(() => data.GetEnumerator()) 

fallirà se gli date un lambda argomento a zero come nell'esempio (almeno la versione che sto usando). Passare un argomento che non viene mai utilizzato consentirà comunque di soddisfare i requisiti di firma.

mockSet.Setup((m => m.GetEnumerator()).Returns(x => data.GetEnumerator()) 

Compilerà tuttavia e funziona come previsto.

E questo vale anche per la risposta di Kelu così (anche se ha aggiunto il lambda nel posto sbagliato.

mockSet.As<IDbAsyncEnumerable<Blog>>() 
     .Setup(m => m.GetAsyncEnumerator()) 
     .Returns(x => new TestDbAsyncEnumerator<Blog>(data.GetEnumerator())); 

Non cercare di nitpick risposte qui, sto solo aggiungendo perché ho fatto questi errori io :)

Problemi correlati