如何使用Moq和Autofixture模拟entity framework6

我正在使用AutoMoq,但由于entity framework(使用dbContext和代码优先) dbContext我有点困惑如何编写我的第一个unit testing

 // 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(); 

当我运行unit testing时,它会崩溃

    在Ploeh.AutoFixture.Kernel.TerminatingSpecimenBuilder.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.RecursionGuard.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.RecursionGuard.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.RecursionGuard.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.AutoPropertiesCommand`1.Execute(Object sample,ISpecimenContext context)
    在Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.RecursionGuard.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.RecursionGuard.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.RecursionGuard.Create(对象请求,ISpecimenContext上下文)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Collections.Generic.List`1..ctor(IEnumerable`1集合)
    在System.Linq.Enumerable.ToList [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.MethodInvoker.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.RecursionGuard.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.Kernel.CompositeSpecimenBuilder.c__DisplayClass6.b__1(ISpecimenBuilder b)
    在System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
    在System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
    在System.Linq.Enumerable.d__a5`1.MoveNext()
    在System.Linq.Enumerable.FirstOrDefault [TSource](IEnumerable`1 source)
    在Ploeh.AutoFixture.Kernel.RecursionGuard.Create(对象请求,ISpecimenContext上下文)
    在Ploeh.AutoFixture.SpecimenFactory.Create [T](ISpecimenContext context,T seed)
    在Ploeh.AutoFixture.SpecimenFactory.Create [T](ISpecimenContext context)
    在PriceServiceTests.cs中的PriceServiceTests.Test_Price_Object_Setup():第26行

编辑

在EF 6中,他们似乎正在使DbSet更具可模仿性。

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

让DbSet更具可模仿性

  • 这意味着添加受保护的构造函数并使方法成为虚拟
  • 请注意,从DbSet派生的使用受保护构造函数的类型将创建一个不绑定到任何上下文的对象,并且这些方法将是no-ops。 从创建测试双精度的角度来看,这非常像IDbSet。
  • 如果我们采用这个选项,我们可能会淘汰IDbSet
  • 值得注意的是,没有发现任何情况,这与使用IDbSet进行测试双打在function上有所不同。 但是,社区中强烈认为接口是首选。

有谁知道如何模拟它?

编辑2

我找到了这篇文章,但它一直在崩溃

 public class MyContext : DbContext { //public GroceryListContext() // : base() //{ //} public virtual DbSet Prices { get; set; } } [Test] public void Test_Price_Object_Setup_Properly() { var mockContext = new Mock(); var mockSet = new Mock<DbSet>(); // 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(); Assert.That(true, Is.EqualTo(false)); } 

除以下exception:

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 'DbSet System.ArgumentException : Type to mock must be an interface or an abstract or non-sealed class. ----> System.TypeLoadException : Method 'Create' on type 'DbSet从程序集’DynamicProxyGenAssembly2,Version = 0.0.0.0,Culture = neutral,PublicKeyToken = a621a9e7e5c32e69′ System.ArgumentException : Type to mock must be an interface or an abstract or non-sealed class. ----> System.TypeLoadException : Method 'Create' on type 'DbSet 1Proxyb409fc6b430b4568aac048b60ea2f02e System.ArgumentException : Type to mock must be an interface or an abstract or non-sealed class. ----> System.TypeLoadException : Method 'Create' on type 'DbSet试图隐式覆盖具有较弱类型参数约束的方法。

您需要提供一个规范 ,指示应该DbSet类(尽管它不是抽象类型或接口)。

原因是因为DbSet类是公共的,但它有一个受保护的构造函数。

规格

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

现在,AutoFixture可以提供自动生成的PriceService值。


请注意, MyContext类也是公共的,而AFAICT也有公共构造函数。 这意味着默认情况下,AutoFixture不会为MyContext类提供自动模拟的实例。

(如果您可以提供您的方案,我可能会进一步提供帮助。)

有一个名为AutoFixture.AutoEF的NuGet包可以解决您的问题

 fixture.Customize(new EntityCustomization(new DbContextEntityTypesProvider(typeof(MyContext))));