Shim DbContext ctor per il test dell'unità di sforzo

effort entity-framework microsoft-fakes shim unit-testing

Domanda

Mi piacerebbe intercettare var context = new MyDbContext() per restituire invece una chiamata al costruttore differente.

Il bello di EFfort è che ti permette di creare un semplice database in memoria per il test delle unità.

var connection = Effort.DbConnectionFactory.CreateTransient();
var testContext = new MyDbContext(connection);

Ma poi dovresti iniettare quel context nel tuo repository.

var connection = Effort.DbConnectionFactory.CreateTransient();
var testContext = new MyDbContext(connection);

È possibile intercettare var context = new MyDbContext() , in modo che restituisca il testContext ?

var connection = Effort.DbConnectionFactory.CreateTransient();
var testContext = new MyDbContext(connection);

Risposta accettata

(Modifica: ho appena realizzato che in realtà non sta restituendo l'altra chiamata del ctor.

Capito. Abbastanza semplice se sai come farlo:

        [TestMethod]
        public void Should_have_a_name_like_this()
        {
            // Arrange
            var connection = Effort.DbConnectionFactory.CreateTransient();
            ShimSolrDbContext.Constructor = context => new SolrDbContext(connection);

            // Act


            // Assert

        }

E come al solito, EFfort richiede questo costruttore nella classe DbContext:

        [TestMethod]
        public void Should_have_a_name_like_this()
        {
            // Arrange
            var connection = Effort.DbConnectionFactory.CreateTransient();
            ShimSolrDbContext.Constructor = context => new SolrDbContext(connection);

            // Act


            // Assert

        }

Ma significa che il repository è beatamente inconsapevole della speciale connessione Transient:

        [TestMethod]
        public void Should_have_a_name_like_this()
        {
            // Arrange
            var connection = Effort.DbConnectionFactory.CreateTransient();
            ShimSolrDbContext.Constructor = context => new SolrDbContext(connection);

            // Act


            // Assert

        }

Risposta popolare

Hai due opzioni possibili. Usando le fabbriche o tramite la programmazione orientata all'aspetto (come PostSharp)

facendo riferimento a questo articolo: http://www.progware.org/Blog/post/Interception-and-Interceptors-in-C-(Aspect-orientated-programming).aspx

Utilizzo di PostSharp (AOP)

PostSharp è un ottimo strumento e può raggiungere l'intercettazione più pulita possibile (ovvero non comporta alcuna modifica nelle classi e nella generazione di oggetti, anche se non sono le tue fabbriche per la creazione e / o l'interfaccia di oggetti) ma non è una libreria libera. Piuttosto che creare proxy in fase di runtime, esso inietta il codice in fase di compilazione e pertanto modifica il programma iniziale in modo semplice per aggiungere l'intercettazione del metodo.
.....
La cosa bella in questo è che non cambierai nient'altro nel tuo codice, quindi il tuo oggetto può ancora essere generato usando la nuova parola chiave.

Utilizzando DI e modello di fabbrica

Personalmente preferisco l'approccio del modello di fabbrica, ma sembra che tu abbia bisogno di iniettare dipendenze nelle tue classi.

public interface IDbContextFactory<T> where T : DbContext {
    T Create();
}

public class TestDbContextFactory : IDbContextFactory<MyDbContext> {
    public MyDbContext Create() {
        var connection = Effort.DbConnectionFactory.CreateTransient();
        var testContext = new MyDbContext(connection);
        return testContext;
    }
}

public class FooRepository {
    MyDbContext _context;
    public FooRepository(IDbContextFactory<MyDbContext> factory) { 
        _context = factory.Create(); 
    }
}



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é