实体框架核心唯一索引测试

时间:2019-03-26 14:33:35

标签: c# unit-testing asp.net-core entity-framework-core

我有一个模型课:

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()中失败了。数据库(context)包含两个对象,它们具有相同的Name

我解决了所有相关问题,但是我没有看到有人回答我的问题。

2 个答案:

答案 0 :(得分:1)

正如其他人指出的那样,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
}

答案 1 :(得分:0)

测试失败,因为第二个var options = { data: ["blue", "green", "pink", "red", "yellow"] }; $("#basics").easyAutocomplete(options); 将引发数据库异常,该异常告诉您不能添加另一个项目,因为它已经包含带有该SaveChanges()的对象。

唯一的约束不会被强制执行。相反,尝试添加重复值将在您尝试执行此操作时引发异常。这样一来,您就可以对它做出实际反应,而不是只在事后注意到它(当您看到尝试添加的数据不存在时)。

您可以使用Name进行测试:

Assert.Throws

您还可以在此处指定确切的异常(我不记得在那上面抛出了哪个异常),也可以将其分配给变量([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); Assert.Throws<Exception>(() => context.SaveChanges()); } } 返回异常),并验证异常消息以确保这是您期望的确切异常。