我正在使用AutoMoq,但由于Entity Framework(使用EF6和Code First),我的第一个单元测试写法有点困惑。
// 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>();
当我运行单元测试时,它会崩溃。
在Ploeh.AutoFixture.Kernel.TerminatingSpecimenBuilder.Create(Object request, ISpecimenContext context)中创建
在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(Object request, ISpecimenContext context)中创建
在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(Object request, ISpecimenContext context)中创建
在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(Object request, ISpecimenContext context)中创建
在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(Object request, ISpecimenContext context)中创建
在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(Object request, ISpecimenContext context)中创建
在Ploeh.AutoFixture.Kernel.AutoPropertiesCommand`1.Execute(Object specimen, ISpecimenContext context)中执行
在Ploeh.AutoFixture.Kernel.Postprocessor`1.Create(Object request, ISpecimenContext context)中创建
在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
编辑
在 EF 6 中,它似乎正在使 DbSet 更易于模拟。
使DbSet更容易模拟
这意味着添加受保护的构造函数并使方法虚拟化。
请注意,使用受保护的构造函数派生自DbSet的类型将创建一个未绑定到任何上下文的对象,并且方法将不起作用。从创建测试替身的角度来看,这使它非常类似于IDbSet。
如果我们采用此选项,我们可能会潜在地过时IDbSet。
值得注意的是,尚未确定任何情况下这与使用IDbSet作为测试替身没有功能上的差异。然而,社区普遍认为接口更受欢迎。
有人知道如何模拟它吗?
编辑2
我找到了this article但它一直崩溃。
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 : 要模拟的类型必须是接口、抽象类或非密封类。 ----> System.TypeLoadException : 来自程序集“DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=a621a9e7e5c32e69”的“DbSet
1Proxyb409fc6b430b4568aac048b60ea2f02e”类型上的“Create”方法试图隐式覆盖具有更弱类型参数约束的方法。