首页 > 解决方案 > 实体框架核心唯一索引测试

问题描述

我有一个模型类:

public class Work
{
    public long Id { get; set; }

    [Required]
    public string Name { get; set; }
}

我希望这Work.Name将是独一无二的,所以我定义了DbContext

public class MyDbContext : DbContext
{
    public MyDbContext () : base() { }
    public MyDbContext (DbContextOptions<MyDbContext > options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Work>(entity =>
            entity.HasIndex(e => e.Name).IsUnique()
        );
    }
    public DbSet<Work> Works { get; set; }
}

我想测试一下,所以我有一个这样的测试:

[Fact]
public void Post_InsertDuplicateWork_ShouldThrowException()
{
    var work = new Work
    {
        Name = "Test Work"
    };

    using (var context = new MyDbContext (options))
    {
        context.Works.Add(work);
        context.SaveChanges();
    }

    using (var context = new MyDbContext (options))
    {
        context.Works.Add(work);
        context.SaveChanges();
    }

    using (var context = new MyDbContext (options))
    {
         Assert.Equal(1, context.Works.Count());
    }
}

(该option对象包含设置InMemoryDatabase

我真的不知道要检查什么,但测试在 中Assert失败,而不是在第二中SaveChanges()。数据库 (the context) 包含两个具有相同Name.

我检查了所有相关问题,但没有看到任何人回答我的问题。

标签: c#unit-testingasp.net-coreentity-framework-core

解决方案


正如其他人指出的那样,InMemory 数据库提供程序忽略了所有可能的约束。
我的建议是使用具有“内存中”功能的 Sqlite 提供程序,这将引发重复唯一键的异常。

public MyDbContext CreateSqliteContext()
{
    var connectionString = 
        new SqliteConnectionStringBuilder { DataSource = ":memory:" }.ToString();
    var connection = new SqliteConnection(connectionString);
    var options = new DbContextOptionsBuilder<MyDbContext>().UseSqlite(connection);

    return new MyDbContext(options);
}

private void Insert(Work work)
{
    using (var context = CreateSqliteContext())
    {
        context.Works.Add(work);
        context.SaveChanges();
    }    
}

[Fact]
public void Post_InsertDuplicateWork_ShouldThrowException()
{
    var work1 = new Work { Name = "Test Work" };
    var work2 = new Work { Name = "Test Work" };

    Insert(work1);

    Action saveDuplicate = () => Insert(work2);

    saveDuplicate.Should().Throw<DbUpdateException>(); // Pass Ok
}

推荐阅读