Тестирование EF Save Changes Modifiers. Передача в DbPropertyValues

Попытка сделать некоторую бизнес-логику в С#, переопределив метод EF SaveChanges.
Идея состоит в том, чтобы иметь некоторые расширенные вычисления для таких вещей, как если бы это поле изменило обновление этого поля. И это поле является суммой подкласса минус некоторые другие поля, вы знаете, продвинутый бизнес-мусор.

Так как это действительно сложно, мы хотим проверить начинку. Добавление тестов отлично работает, но обновление, которое мы не можем тестировать, поскольку мы написали интерфейс, в котором этот метод передан Подпись выглядит так:

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 ​​или обновить для наших тестов. Пожалуйста, помогите нам выяснить, как проверить этот метод.

Ответы

Ответ 1

Я решил, что лучший способ - изменить ожидаемую стратегию. Вместо

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

Ответ 2

Если у вас есть Visual Studio 2012 Update 2+, вы можете "Добавить сборку подделок" для EntityFramework, щелкнув правой кнопкой мыши ссылку на проект в вашем тестовом проекте.

После добавления вы можете создавать экземпляры System.Data.Entity.Infrastructure.Fakes.ShimDbPropertyValues, которые полностью находятся под вашим контролем. например

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

И когда GetString вызывается на этот подделка /shim DbPropertyValues, он вернет "Hello, World!".

Подробнее здесь: https://msdn.microsoft.com/en-us/library/hh549175.aspx