2015-10-14 10 views
14

Provare a fare qualche logica di business in C# sovrascrivendo il metodo EF SaveChanges.
L'idea è di avere alcuni calcoli avanzati su cose come se questo campo avesse cambiato aggiornare questo campo. E questo campo è la somma della sottoclasse meno alcuni altri campi, sai spazzatura business avanzata.Test EF Modificatori modifiche di salvataggio. Passare in DbPropertyValues ​​

Dal momento che è davvero complicato, vogliamo testare il riempimento. L'aggiunta di prove di grande lavoro ma quelli di aggiornamento non riesco a testare come abbiamo scritto un'interfaccia in cui è passato il metodo in questione Firma assomiglia a questo

void Update(object entity, DbPropertyValues currentValues, DbPropertyValues originalValues); 

Quando si chiama per intero EF funziona splendidamente

public override int SaveChanges() 
    { 
     var added = ChangeTracker.Entries().Where(p => p.State == EntityState.Added).Select(p => p.Entity); 
     var updated = ChangeTracker.Entries().Where(p => p.State == EntityState.Modified).Select(p => p); 

     var context = new ChangeAndValidationContext(); 

     foreach (var item in added) 
     { 
      var strategy = context.SelectStrategy(item); 
      strategy.Add(item); 
     } 

     foreach (var item in updated) 
     { 
      var strategy = context.SelectStrategy(item); 
      strategy.Update(item.Entity, item.CurrentValues, item.OriginalValues); 
     } 
     return base.SaveChanges(); 
    } 

Non siamo in grado di capire come passare in DbPropertyValues ​​originale o aggiornato per i nostri test. Per favore aiutaci a capire come testare quel metodo.

risposta

4

ho deciso il modo migliore era quello di cambiare ciò che la strategia del previsto. Invece di

void Update(object entity, DbPropertyValues currentValues, DbPropertyValues originalValues); 

ho fatto accettare

void Update(object entity, Dictionary<string, object> currentValues, Dictionary<string, object> originalValues); 

che significa che ho cambiato i valori passati al metodo di aggiornamento

foreach (var item in updated) 
{ 
     var strategy = context.SelectStrategy(item); 
     strategy.Update(item.Entity, item.CurrentValues.ValuesToValuesDictionary(), item.OriginalValues.ValuesToValuesDictionary()); 
} 

Poi ho creato quel metodo di estensione

public static class DbPropertyValueExtensions 
{ 
    public static Dictionary<string, object> ValuesToValuesDictionary(this DbPropertyValues vals) 
    { 
     var retVal = new Dictionary<string, object>(); 
     foreach (var propertyName in vals.PropertyNames) 
     { 
      if (!retVal.ContainsKey(propertyName)) 
      { 
       retVal.Add(propertyName, vals[propertyName]); 
      } 

     } 
     return retVal; 
    } 
} 

Che significava che i miei test dovevano passare in quei dizionari.

[Test] 
    public void DateLastModifiedUpdatesOnUpdate() 
    { 
     //Arrange 
     var toTest = LossFactoryHelper.Create(); 
     var lossCheckAndValidationAddStrategy = new LossChangeAndValidationStrategy(); 
     var now = DateTime.UtcNow; 
     var originalValues = toTest.GetValuesNow(); 
     //Act 


     toTest.mny_deductible = -1; 
     var currentValues = toTest.GetValuesNow(); 
     lossCheckAndValidationAddStrategy.Update(toTest, originalValues, currentValues); 

     //Assert 
     Assert.GreaterOrEqual(toTest.clc_DateLastModified, now); 
    } 

E il metodo di estensione per contribuire a ottenere un'istantanea dei valori come non dover creare il dizionario più e più

public static class ReflectionToGetCurrentValuesExtension 
{ 
    public static Dictionary<string, object> GetValuesNow(this object obj) 
    { 
     var retVal = new Dictionary<string, object>(); 
     var type = obj.GetType(); 
     PropertyInfo[] properties = type.GetProperties(); 
     foreach (PropertyInfo property in properties) 
     { 
      if (property.CanRead && property.CanWrite) 
      { 
       if (!retVal.ContainsKey(property.Name)) 
       { 
        retVal.Add(property.Name, property.GetValue(obj)); 
       } 
      } 
     } 
     return retVal; 
    } 
} 
5

Se si dispone di Visual Studio 2012 Update 2+, è possibile "Aggiungi gruppo di falsi" per EntityFramework facendo clic con il pulsante destro del mouse sul riferimento del progetto nel progetto di test.

Una volta aggiunto, è possibile creare istanze di System.Data.Entity.Infrastructure.Fakes.ShimDbPropertyValues completamente sotto il proprio controllo. per esempio.

var shim = new System.Data.Entity.Infrastructure.Fakes.ShimDbPropertyValues(); 
shim.ItemGetString = s => "Hello, World!"; 

E quando GetString viene chiamato su quel finto/shim DbPropertyValues tornerà "Ciao, mondo!".

Maggiori dettagli qui: https://msdn.microsoft.com/en-us/library/hh549175.aspx