Как создать макет Entity Framework 6 с помощью Moq и Autofixture

Я использую AutoMoq, но я немного не понимаю, как написать свой первый модульный тест из-за Entity Framework (сначала с использованием EF6 и кода) dbContext

// in service class(constructor)
private readonly MyContext context;

public PriceService(MyContext context)
{
    this.context = context;
}

// following would be in nunit test method.
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var priceService = fixture.Create<PriceService>();

Когда я запускаю модульный тест, он вылетает

    at Ploeh.AutoFixture.Kernel.TerminatingSpecimenBuilder.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.AutoPropertiesCommand`1.Execute(Object specimen, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
    at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.MethodInvoker.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    at System.Linq.Enumerable.d__a5`1.MoveNext()
    at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
    at Ploeh.AutoFixture.Kernel.RecursionGuard.Create(Object request, ISpecimenContext context)
    at Ploeh.AutoFixture.SpecimenFactory.Create[T](ISpecimenContext context, T seed)
    at Ploeh.AutoFixture.SpecimenFactory.Create[T](ISpecimenContext context)
    at PriceServiceTests.Test_Price_Object_Setup() in PriceServiceTests.cs:line 26

Редактировать

В EF 6 похоже, что они делают DbSet более подделываемым.

https://entityframework.codeplex.com/wikipage?title=Design%20Meeting%20Notes%20-%20May%2016,%202013

Сделайте DbSet более издеваемым

  • Это означает добавление защищенного конструктора и создание виртуальных методов.
  • Обратите внимание, что тип, производный от DbSet, который использует защищенный конструктор, создаст объект, не привязанный к какому-либо контексту, и методы будут неактивными. Это делает его очень похожим на IDbSet с точки зрения создания тестовых двойников.
  • Если бы мы выбрали эту опцию, мы могли бы потенциально устареть IDbSet
  • Стоит отметить, что не было выявлено случаев, когда это функционально отличалось бы от использования IDbSet для тестовых двойников. Однако в сообществе существует твердое убеждение, что интерфейсы предпочтительнее.

Кто-нибудь знает, как это сделать?

Редактировать 2

Я нашел эту статью, но она продолжает вылетать

public class MyContext : DbContext
{
    //public GroceryListContext()
    //    : base()
    //{

    //}
    public virtual DbSet<Price> Prices { get; set; }
}

[Test]
public void Test_Price_Object_Setup_Properly()
{
    var mockContext = new Mock<MyContext>();

    var mockSet = new Mock<DbSet<Price>>(); // had to add EF to my test solution.
    mockContext.Setup(m => m.Prices).Returns(mockSet.Object);
    var service = new PriceService(mockContext.Object);

    // dies when using autofixture so thought try first moq like in article
   //var priceService = fixture.Create<PriceService>();

   Assert.That(true, Is.EqualTo(false));
}

за следующим исключением:

MyContext.Tests.Services.PriceServiceTests.Test_If_Price_Object_Setup_Properly: System.ArgumentException : Type to mock must be an interface or an abstract or non-sealed class. ----> System.TypeLoadException : Method 'Create' on type 'DbSet1Proxyb409fc6b430b4568aac048b60ea2f02e 'из сборки' Параметр DynamicProxyGenAssembly2, Version = 0.0.0.0, Version = 0.0.0.0, переменный тип параметра DynamicProxyGenAssembly2, Version = 0.0.0.0, Culturecoke21e.affect = 0.0.0.0, Culturecokeey`


person chobo2    schedule 11.10.2013    source источник
comment
связанные: stackoverflow.com/questions/16696777/ и stackoverflow.com/questions/14391146/ и autofixture.codeplex.com/discussions/262557 Вопрос: Вы выявили, что EF6 на самом деле ведет себя иначе, чем 5, или вы просто пытаетесь закончить?   -  person Ruben Bartelink    schedule 12.10.2013
comment
Последний приведенный вами пример без AutoFixture работает на моей машине. Я скопировал ваши классы PriceService, MyContext и метод Test_Price_Object_Setup_Properly. Я реализовал свой собственный класс Price, поскольку вы его не предоставили, и он работает без каких-либо исключений. Я использую Entity Framework 6.0 RC 1 и Visual Studio 2013 RC.   -  person Olav Nybø    schedule 12.10.2013
comment
@RubenBartelink Ну, мой вопрос начался с того, как просто смоделировать Datacontext, тогда я обнаружил, что EF может издеваться над dbset и не нуждается в оболочке. Я столкнулся с огромными проблемами при выполнении учебника. Теперь я знаю, что проблема была в автофиксации. Он устанавливает версию 3.0 moq, но для работы учебника требуется 4.0. Я не уверен, можно ли сейчас использовать автофиксацию из-за этого.   -  person chobo2    schedule 13.10.2013
comment
@ OlavNybø - Да, теперь он работает на моей машине, так как вы, вероятно, только что установили moq прямо из его пакета nuget. Я получил его от autofixture, который устанавливает версию 3, и вам нужна версия moq 4 для работы этого фрагмента кода.   -  person chobo2    schedule 13.10.2013
comment
@chobo Хорошо, что он у вас сейчас работает, и, кажется, нехорошо, это стоило вам времени, чтобы добраться туда. Как правило, AutoFixture зависит от самой ранней версии, которая должна пройти тесты. Если вам нужен Moq v4, потому что у вас есть библиотека со странной зависимостью. Должен ли AutoFixture.Xunit требовать 1.9.2, потому что 1.8 не работает с Tech Z? IOW Я думаю, что важно и полезно, что AF не вызывает зависимости от того, что не является абсолютно необходимым (например, версия 3.0+ в .NET 4 недавно вызвала у меня почти дневное бритье яка, но у меня была возможность проголосовать за то, было в порядке   -  person Ruben Bartelink    schedule 13.10.2013


Ответы (2)


Вам необходимо предоставить спецификацию, в которой указано, что класс DbSet<T> должен быть высмеянным (хотя это не абстрактная тип или интерфейс).

Причина в том, что класс DbSet<T> является общедоступным, но имеет защищенный конструктор.

Спецификация:

internal class DbSetTypeSpecification : IRequestSpecification
{
    public bool IsSatisfiedBy(object request)
    {
        var type = request as Type;
        if (type == null)
            return false;

        return type.IsGenericType
            && typeof(DbSet<>) == type.GetGenericTypeDefinition();
    }
}

Пример:

[Fact]
public void Test()
{
    var fixture = new Fixture();
    fixture.ResidueCollectors.Add(
        new MockRelay(
            new DbSetTypeSpecification()));

    Assert.DoesNotThrow(() => 
        fixture.Create<PriceService>());
}

Теперь AutoFixture может предоставлять автоматически сгенерированные значения PriceService.


Обратите внимание, что класс MyContext также является общедоступным и, AFAICT, у него также есть открытый конструктор. Это означает, что AutoFixture по умолчанию не будет предоставлять экземпляр с автоизменением для класса MyContext.

(Если вы предоставите свой сценарий, я смогу вам помочь.)

person Nikos Baxevanis    schedule 12.10.2013
comment
Вы пробовали это против EF 6? Я обнаружил, что причина, по которой у меня ничего не работало, заключалась в том, что AutoFixture установила moq 3, и мне нужен moq 4 для работы учебника. Я пытался сохранить moq 4 и autofixture, но так и не смог импортировать Fixture, используя. - person chobo2; 13.10.2013
comment
Ну, я просто смотрю на Autofixture, никогда не использовал его раньше. Я хочу настроить свои тесты, чтобы мне не приходилось вручную создавать все макеты (с moq) и фиктивные данные. Это то, что я пытаюсь сделать. Я также немного не понимаю, когда мне нужно, чтобы определенные данные в моем макете имели определенное значение (скажем, цена в PriceObject должна быть 5). - person chobo2; 13.10.2013
comment
@ chobo2 О Moq, пожалуйста, прочтите мой ответ здесь. - person Nikos Baxevanis; 13.10.2013
comment
Никос, ты получил от меня +1, даже если другие более ценны своими щелчками :) @ chobo2 NB убедитесь, что вы посмотрите на различные вопросы и ответы SO, которые повторно генерируют тестовые данные, возвращаемые через интерфейсы Moqed (Moq по сути не делает этого) t предоставляют способ глобально перехватить генерацию возвращаемого значения, поэтому вам нужно понимать, когда / как / где вы можете вводить соответствующие настройки для каждого теста). (Во многих из этих публикаций обычно задействован EF - он часто заставляет людей перестать думать, что делать, чтобы изолировать проблемы. Крайне важно всегда быть уверенным, что тесты не проходят по правильной причине - особенно с автоматизацией) - person Ruben Bartelink; 13.10.2013
comment
@NikosBaxevanis - Да, я видел ваш пост, я понял, почему он у меня не работает. Я сказал nuget не получать зависимости, и это включало Autofixture, поэтому он получил только AutoFixture.moq, поэтому namepsaces не импортирует. - person chobo2; 13.10.2013

Существует пакет NuGet под названием AutoFixture.AutoEF, который может решить вашу проблему.

fixture.Customize(new EntityCustomization(new DbContextEntityTypesProvider(typeof(MyContext))));
person Shevek    schedule 23.07.2015