为内存中的DbContext设置自动修复程序

问题描述 投票:0回答:1

[我目前正在尝试使用Autofixture创建一个预定义的夹具,作为使用ICustomization的ApplicationDbContext的In-Memory provider的实现。

public class ApplicationDbContextFixture : ICustomization
{
    public void Customize(IFixture fixture)
    {
        var specimenFactory = new SpecimenFactory<ApplicationDbContext>(CreateDbContext);
        fixture.Customize<ApplicationDbContext>(
                composer =>
                    composer.FromFactory(specimenFactory)
                );
    }

    /// <summary>
    /// Private factory method to create a new instance of <see cref="ApplicationDbContext"/>
    /// </summary>
    private ApplicationDbContext CreateDbContext()
    {
        var dbContextOptions = new DbContextOptionsBuilder<ApplicationDbContext>()
                    .UseInMemoryDatabase("SomeDatabaseName")
                    .Options;
        var dbContext = new ApplicationDbContext(dbContextOptions);        
        return dbContext;
    }
}

然后,我将按照以下方式将该定制应用于我的治具:

    [Fact]
    public void TestAddUsersToEmptyDatabase()
    {
        // Arrange
        // Fixture for ApplicationDbContext
        var fixture = FixtureFactory.CreateFixture();
        var applicationDatabaseFixture = new ApplicationDbContextFixture();
        fixture.Customize(applicationDatabaseFixture);

        // Fixture for users
        var randomUser = fixture.Create<AppUser>();
        var normalUser = fixture.Create<AppUser>();
        var adminUser = fixture.Create<AppUser>();

        // Act & Assert
        // Run the test against one instance of the context
        // Use a clean instance of the context for each operation too
        using (var dbContext = fixture.Create<ApplicationDbContext>())
        {
            Assert.Empty(dbContext.Users);
            dbContext.Users.Add(randomUser);
            dbContext.SaveChanges();
        }

        using (var dbContext = fixture.Create<ApplicationDbContext>())
        {
            dbContext.Users.AddRange(normalUser, adminUser);
            dbContext.SaveChanges();
        }

        using (var dbContext = fixture.Create<ApplicationDbContext>())
        {
            Assert.NotEmpty(dbContext.Users);
            Assert.NotNull(dbContext.Users.SingleOrDefault(_ => _.Id == randomUser.Id));
            Assert.NotNull(dbContext.Users.SingleOrDefault(_ => _.Id == normalUser.Id));
            Assert.NotNull(dbContext.Users.SingleOrDefault(_ => _.Id == adminUser.Id));
        }
    }

FixtureFactory.CreateFixture实现

    /// <summary>
    /// Factory method to declare a single <see cref="IFixture"/> for unit tests applications
    /// </summary>
    internal static class FixtureFactory
    {
        internal static IFixture CreateFixture()
        {
            var fixture = new Fixture().Customize(
                new AutoMoqCustomization { ConfigureMembers = true });

            return fixture;
        }
    }

现在在我的单元测试中,断言Assert.Empty(dbContext.Users);将抛出System.NotImplementedException : The method or operation is not implemented.,因为从Autofixture生成的DbSet<AppUser> Users是DynamicProxy。

查看图像dbContext.Users as DynamicProxy

奇怪的是,如果我检查从CreateDbContext()调用的工厂方法(即fixture.Create<ApplicationDbContext>())的断点,则DbSet用户是预期的类型。

查看图像dbContext.Users as InternalDbSet

[可选,我知道我可以将dbContext.Users的所有用法替换为dbContext.Set<User>(),这将使单元测试通过,但问题是在实际的类中,我将dbContext.Users用于IQueryables ]和数据库操作,因此如果可能,我仍然需要坚持使用它。

因此,我需要帮助来了解为什么AutoFixture为什么使用工厂方法为ApplicationDbContext生成实例,但是其中的所有DbSet<>属性在由ISpecimenBuilder解析时都会被模拟。有没有办法解决这个问题?

我已经在their Github中发布了类似的问题,但该问题最近并未激活,所以我也在这里问过。

[请注意,我是2天前才开始使用Autofixture的。因此,如果在某些“设计模式”中我写错了什么或存在误解,请发表评论,以备不时之需。

更新1:因此,我尝试使用没有任何AutoMoq定制(即fixture = new Fixture())的初始化普通灯具,这一次它抛出AutoFixture.ObjectCreationExceptionWithPath异常,抱怨它无法解析ApplicationDbContext中的DbSet属性。在这一点上,我在想是否有人知道如何使用Relay或ISpecimenBuilder告诉Autofixture使用DbSet<T>来使用/调用/实现ApplicationDbContext中的所有dbContext.Set<T>属性,因为如果我替换了DbSet中的所有用法,那将起作用我的单元测试,但是正如我提到的,所有IQueryable都是从DbSets返回的,所以我不能简单地在ApplicationDbContext中替换它。

更新2:我从工厂方法CreateDbContext()中删除并简化了ApplicationDbContext的创建,因为这将导致代码复杂性的混淆。

c# entity-framework mocking entity-framework-core autofixture
1个回答
0
投票

很难理解您要通过帖子实现的目标。

我认为您真正需要的是测试恰好使用EntityFramework的代码。如果是这种情况,您可能想看看这个库,我已经创建了EntityFrameworkCore.AutoFixture。它使用内存数据库提供程序以及SQLite内存提供程序。

查看一些代码示例的自述文件。如果您有任何疑问,请给我发消息或在GitHub上发布问题。

© www.soinside.com 2019 - 2024. All rights reserved.