2015-10-14 98 views
14

试图通过覆盖EF SaveChanges方法在C#中执行一些业务逻辑。
这个想法是有一些高级的计算,如果这个领域已经改变了更新这个领域。这个领域是子类减去其他领域的总和,你知道高级商业垃圾。测试EF保存更改修饰符。传入DbPropertyValues

由于它非常复杂,我们想测试它的填充。添加测试工作的伟大,但似乎该更新那些我们无法测试,因为我们已经写在这里讨论的方法传递 签名看起来像这样

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

当全EF调用它,它精美的作品

接口
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(); 
    } 

我们无法弄清楚如何传递DbPropertyValues原始文件或更新测试。请帮助我们弄清楚如何测试该方法。

回答

4

我决定更好的办法是改变战略所期望的。取而代之的

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

我把它接受

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

这意味着我改变了传递到更新方法

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

值然后我创建的扩展方法

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; 
    } 
} 

这意味着什么我的测试需要通过这些字典。

[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); 
    } 

和扩展方法,以帮助该值不是一个快照必须在创建字典和超过

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

如果您有Visual Studio 2012更新2+,则可以通过右键单击测试项目中的项目引用来为EntityFramework“添加虚假装配”。

添加后,您可以创建完全在您控制之下的System.Data.Entity.Infrastructure.Fakes.ShimDbPropertyValues实例。例如

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

GetString上调用,假冒/垫片DbPropertyValues它将返回“你好,世界!”。

更多细节在这里:https://msdn.microsoft.com/en-us/library/hh549175.aspx