Entity Framework 4.3 и Moq не могут создавать DbContext mock
Следующий тест, который работал с EF 4.2, теперь вызывает следующее исключение с EF 4.3
System.ArgumentException: тип для mock должен быть интерфейсом или абстрактного или непечатаемого класса. ---- > System.TypeLoadException: Метод "CallValidateEntity" в типе "Castle.Proxies.DbContext43Proxy" из сборки 'DynamicProxyGenAssembly2, Version = 0.0.0.0, Culture = neutral, PublicKeyToken = null 'отменяет метод, который не видно из этой сборки.
[Test]
public void CanCreateMoqTest()
{
// Arrange
Mock<DbContext43> mock;
// Act
mock = new Mock<DbContext43>();
// Assert
Assert.NotNull(mock.Object);
}
public class DbContext43:DbContext
{
}
Что мне делать? Создать интерфейс для моего DbContext43?
Является ли это изменением между 4.2 и 4.3?
Спасибо!!
Ответы
Ответ 1
Спасибо, что нашли это. Проблема вызвана атрибутами InternalsVisibleTo, которые мы удалили из выпуска EF 4.2, но остались в EF 4.3. Это позволило Moq (который мы используем для наших тестов), чтобы увидеть внутренности EntityFramework.dll. Однако, поскольку ваша сборка не может видеть эти внутренние элементы, вы попали в исключение.
Мы планируем сделать выпуск патча EF 4.3 в течение следующих нескольких недель и будем лишать InternalsVisibleTo из этой версии, после чего издевательство должно работать снова.
Обновление: теперь это исправлено в EF 4.3.1 (и EF 5.0-beta1), выпущенном сегодня. Обновите пакет NuGet, чтобы получить исправление. Подробнее см. http://blogs.msdn.com/b/adonet/archive/2012/02/29/ef4-3-1-and-ef5-beta-1-available-on-nuget.aspx.
Ответ 2
Этот вид исключения обычно указывает, что элемент, который вы пытаетесь переопределить, не отображается как часть открытого интерфейса в данной сборке (а может быть, точнее - переопределение сборки не видит его). И если мы посмотрим в CallValidateEntity
реализации в EntityFramework 4.3:
internal virtual DbEntityValidationResult CallValidateEntity(
DbEntityEntry entityEntry, IDictionary<object, object> items)
{
return this.ValidateEntity(entityEntry, items);
}
Мы действительно замечаем, что этот метод internal
, и в результате попадает в категорию без переопределения (используется атрибут non-overridable с учетом атрибута InternalsVisibleTo
). Это, естественно, соответствует правильной записи метаданных:
Method #20 (06000a03)
-------------------------------------------------------
MethodName: CallValidateEntity (06000A03)
Flags : [Assem] [Virtual] [HideBySig] [NewSlot] (000003c3)
Непонятно, почему Moq пытается переопределить этого участника... учитывая, что он не должен видеть его на первом месте.
Обертка вашего контекста в интерфейсе и использование только тех методов, которые вы используете, является жизнеспособным вариантом - этого должно быть достаточно, чтобы пройти тест.