6

我正在使用AutoMoq,但由于实体框架(首先使用 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>();

当我运行单元测试时它崩溃了

    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 Ploeh.AutoFixture.Kernel.RecursionGuard.Create(对象请求,ISpecimenContext 上下文)
    在 Ploeh.AutoFixture.Kernel.AutoPropertiesCommand`1.Execute(对象标本,ISpecimenContext 上下文)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 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 源)
    在 Ploeh.AutoFixture.Kernel.RecursionGuard.Create(对象请求,ISpecimenContext 上下文)
    在 Ploeh.AutoFixture.SpecimenFactory.Create[T](ISpecimenContext 上下文,T 种子)
    在 Ploeh.AutoFixture.SpecimenFactory.Create[T](ISpecimenContext 上下文)
    在 PriceServiceTests.cs:line 26 中的 PriceServiceTests.Test_Price_Object_Setup()

编辑

在 EF 6 中,它们似乎使 DbSet 更加可模拟。

https://entityframework.codeplex.com/wikipage?title=Design%20Meeting%20Notes%20-%20May%2016%2c%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, Culture=neutral, PublicKeyToken=a621a9e7e5c32e69' 试图隐式覆盖具有较弱类型参数约束的方法。

4

2 回答 2

4

您需要提供一个说明该类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类提供自动模拟实例。

(如果你能提供你的场景,我可能会提供进一步的帮助。)

于 2013-10-12T14:40:14.933 回答
1

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

fixture.Customize(new EntityCustomization(new DbContextEntityTypesProvider(typeof(MyContext))));
于 2015-07-23T12:57:36.097 回答