测试EF保存更改修改器。传入DbPropertyValues

时间:2015-10-14 07:49:02

标签: c# tdd entity-framework-6

尝试通过覆盖EF SaveChanges方法在C#中执行一些业务逻辑 我们的想法是对事情进行一些高级计算,例如,如果此字段已更改,请更新此字段。而且这个字段是子类减去其他一些字段的总和,你知道高级商业垃圾。

由于它真的很复杂,我们想测试它的填充物。添加测试工作得很好但是我们似乎无法测试更新的测试,因为我们已经编写了一个接口,其中传递了相关方法 签名看起来像这样

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原始版本或更新我们的测试。请帮助我们弄清楚如何测试该方法。

2 个答案:

答案 0 :(得分:5)

如果您有Visual Studio 2012 Update 2+,则可以通过右键单击测试项目中的项目引用来为EntityFramework“添加Fakes Assembly”。

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

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

当假冒/垫片GetString上调用DbPropertyValues时,它将返回“Hello,World!”。

此处有更多详情:https://msdn.microsoft.com/en-us/library/hh549175.aspx

答案 1 :(得分:4)

我认为更好的方法是改变策略的预期。而不是

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

我接受了

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

这意味着我更改了传递给Update Method的值

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

和Extension方法一起帮助获取值的快照,而不必一遍又一遍地创建字典

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