Effort- FirstOrDefault restituisce null quando Faking Database

c# effort entity-framework mocking unit-testing

Domanda

Sto provando a creare alcuni test unitari per il mio progetto, dopo aver scavato molto in giro ho trovato Effort, l'idea è fantastica, prende in giro il database invece di occuparsi di simulare il DBContext che tra l'altro è davvero difficile farlo bene quando utilizzando uno schema complesso.

Tuttavia sto cercando di ottenere l'e-mail di un utente dopo che l'ho specificamente aggiunto al database in memoria creato da Effort, ecco il codice

MyContext contextx = new MyContext(Effort.DbConnectionFactory.CreateTransient());

var client = new Client
{
    ClientId = 2,
    PersonId = 3,
    Person = new Person
    {
        PersonId = 3,
        EMail = "xxxxx@gmail.com"
    }
};
contextx.Client.Add(client); //<-- client got added, I checked it and is there

var email = contextx.Client.Select(c => c.Person.EMail).FirstOrDefault(); 

Nell'ultima riga sopra non riesco a farlo per restituire l'email xxxx@gmail.com invece restituisce sempre null.

Qualche idea?

Risposta accettata

Rispondere alla tua domanda diretta

Per la domanda specifica che hai chiesto, vorrei suggerire due cose:

  1. Dai un'occhiata a contextx.Client.ToArray() e guarda quanti membri hai davvero in quella collezione. Potrebbe essere che la raccolta Client sia effettivamente vuota, nel qual caso otterrai effettivamente nulla. Oppure, potrebbe essere che il primo elemento nella raccolta Client abbia un valore nullo per EMail .

  2. Come cambia il comportamento se si chiama contextx.SaveChanges() prima di interrogare la raccolta Client su DbContext? Sono curioso di vedere se chiamare SaveChanges farà sì che il valore appena inserito esista nella collezione. Questo in realtà non dovrebbe essere richiesto, ma potrebbe esserci qualche strana interazione tra Effort e DbContext .

EDIT: SaveChanges() risulta essere la risposta.

Suggerimenti generali per i test

Dal momento che hai inserito questa domanda con il tag "unit-testing", offrirò alcuni consigli generali sui test delle unità in base ai miei dieci anni trascorsi come unità di test per praticanti e allenatori. I test unitari riguardano la verifica di varie piccole parti della vostra applicazione in isolamento. In genere ciò significa che i test di unità interagiscono solo con alcune classi contemporaneamente. Ciò significa anche che i test di unità non dovrebbero dipendere da librerie o dipendenze esterne (come il database). Viceversa, un test di integrazione esercita più parti del sistema contemporaneamente e può avere dipendenze esterne su cose come i database.

Anche se questo può sembrare un cavillo sulla terminologia, i termini sono importanti per trasmettere l'effettiva intenzione dei tuoi test agli altri membri della tua squadra.

In questo caso, o stai davvero cercando di testare alcune funzionalità che dipendono da DbContext, o stai provando a testare il tuo livello di accesso ai dati. Se stai provando a scrivere un test di unità isolato su qualcosa che dipende direttamente da DbContext, devi interrompere la dipendenza da DbContext. Spiegherò quanto segue in Breaking the Dependency su DbContext di seguito. Altrimenti, stai davvero provando a integrare test del tuo DbContext incluso il modo in cui le tue entità sono mappate. In questo caso, ho sempre trovato il modo migliore per isolare questi test e utilizzare un vero database (locale). Probabilmente vuoi utilizzare un database installato localmente della stessa varietà che stai utilizzando in produzione. Spesso, SqlExpress funziona bene. Puntare i test su un'istanza del database che i test possono eliminare completamente. Lascia che i tuoi test rimuovano tutti i dati esistenti prima di eseguire ogni test. Quindi, possono impostare i dati di cui hanno bisogno senza preoccuparsi che i dati esistenti possano entrare in conflitto.

Rompere la dipendenza da DbContext

Quindi, come si scrivono buoni test unitari quando la logica aziendale dipende dall'accesso a DbContext ? Non lo fai.

Nelle mie applicazioni che utilizzano Entity Framework per la persistenza dei dati, mi assicuro che l'accesso a DbContext sia contenuto in un progetto di accesso ai dati separato. Tipicamente, creerò le classi che implementano il pattern Repository e quelle classi possono prendere una dipendenza da DbContext . Quindi, in questo caso, IClientRepository un ClientRepository che implementa un'interfaccia IClientRepository . L'interfaccia sarebbe simile a questa:

public interface IClientRepository {

    Client GetClientByEMail(string email);

}

Quindi, qualsiasi classe che abbia bisogno di accedere al metodo può essere sottoposta a test dell'unità usando uno stub / mock di base / qualunque. Nulla deve preoccuparsi di DbContext in giro DbContext . Il tuo livello di accesso ai dati è contenuto e puoi testarlo accuratamente utilizzando un vero database. Per alcuni suggerimenti su come testare il livello di accesso ai dati, vedi sopra.

Come ulteriore vantaggio, l'implementazione di questa interfaccia definisce cosa significa trovare un Client per indirizzo e-mail in un unico luogo unificato. L'interfaccia IClientRepository ti consente di rispondere rapidamente alla domanda "Come IClientRepository entità Client nel nostro sistema?"

Prendendo una dipendenza da DbContext è più o meno la stessa scala di un problema di test che consente alle classi di dominio di prendere una dipendenza dalla stringa di connessione e di avere il codice ADO.Net ovunque. Significa che devi creare un vero archivio di dati (anche con un db falso) contenente dati reali. Tuttavia, se si contiene l'accesso a DbContext all'interno di un assembly specifico per l'accesso ai dati, si scoprirà che i test delle unità sono molto più facili da scrivere.

Per quanto riguarda l'organizzazione del progetto, in genere autorizzo il mio progetto di accesso ai dati solo a fare riferimento a Entity Framework. Avrò un progetto Core separato in cui definisco le entità. Definirò anche le interfacce di accesso ai dati nel progetto Core. Quindi, le implementazioni dell'interfaccia concreta vengono inserite nel progetto di accesso ai dati. La maggior parte dei progetti nella soluzione può quindi semplicemente prendere una dipendenza dal progetto Core e solo il file eseguibile o il progetto Web di livello superiore deve realmente dipendere dal progetto di accesso ai dati.




Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché