使用 IdentityDbContext 进行单元测试 Entity Framework 6

Unit testing Entity Framework 6 with IdentityDbContext

我目前正在为我的 ASP.NET Web API 2.0 应用程序中的 Entity Framework 6 个操作添加单元测试,使用以下 MSDN 教程:

http://msdn.microsoft.com/en-us/data/dn314431

教程建议创建一个接口来代替应用程序的 DbContext class。然后在整个应用程序中使用此接口,允许使用 'mocked' 测试上下文测试控制器。

以下是教程中建议的界面:

public interface IBloggingContext 
{ 
    DbSet<Blog> Blogs { get; } 
    DbSet<Post> Posts { get; } 
    int SaveChanges(); 
}

由于我使用的是 SaveChangesAsync(),因此我已将界面修改为以下界面:

public interface IApplicationDbContext : IDisposable
{
    DbSet<Blog> Blogs { get; } 
    DbSet<Post> Posts { get; } 
    Task<int> SaveChangesAsync();
}

不幸的是,本教程假定上下文具有 DbContext 的基础 class,而我的使用 IdentityDbContext 作为其基础 class(见下文)。似乎无法从我的上下文调用 SaveChangesAsync() - 我正在使用它代替 SaveChanges() - 使其无法正确实现接口。

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {

    }

    public Task<int> SaveChangesAsync()
    {
        // No way to call DbContext.SaveChangesAsync() from here
    }
}

如有任何想法或建议,我们将不胜感激!

编辑:

以下是目前正在使用的 classes 的副本:

ApplicationDbContext

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {

    }

    public Task<int> SaveChangesAsync()
    {
        // Cannot resolve base.SaveChangesAsync() from here
    }

    public DbSet<Product> Products { get; set; }
}

IApplicationDbContext

public interface IApplicationDbContext
{
    Task<int> SaveChangesAsync();
    DbSet<Product> Products { get; set; }
}

示例控制器构造函数(使用接口)

protected BaseEntityController(IApplicationDbContext context)
{
    db = context;
}

编辑 2:

class 层次结构似乎确实存在问题。下面是另一个(希望相关的)构建错误:

UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));

Error   2   Argument 1: cannot convert from 'IApplicationDbContext' to 'System.Data.Entity.DbContext'

作为参考,我的 ApplicationUser class 的基础 class 为 IdentityUser:

public class ApplicationUser : IdentityUser

编辑 3:

正如 Jon 所提到的,EDIT 2 中发布的错误是意料之中的。不幸的是,该错误还发生在上下文本身 (ApplicationDbContext) 而不是仅发生在接口 (IApplicationDbContext) 上。

问题现已解决,但只能从解决方案中卸载并重新安装包,重新启动 Visual Studio,然后重建项目。我仍然不确定问题的确切原因。

我已将 Jon 的回答标记为正确,因为它在正常情况下是正确的。

根据 MSDN here IdentityDbContext 继承自 DbContext。因此,如果您需要直接调用,那么 base.SaveChangesAsync 应该可以。

但是,实际上您不需要实现该方法,因为它已经由 DbContext 在 "real" 上下文中实现,除非您使用显式接口实现或添加更多代码 (您不在示例中)。您确实需要在 TestDbContext 中实现一些东西,因为它不会继承自 DbContext。

如果我像你这样实现 SaveChangesAsync

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
{
    public Task<int> SaveChangesAsync()
    {
        return base.SaveChangesAsync();

        // No way to call DbContext.SaveChangesAsync() from here
    }
}

然后在构建时我收到此警告:

Warning 1 'SOWorking.ApplicationDbContext.SaveChangesAsync()' hides inherited member 'System.Data.Entity.DbContext.SaveChangesAsync()'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword.

如果我完全省略 SaveChangesAsync 的实现,或者像这样添加重写,构建没有警告:

public override Task<int> SaveChangesAsync()
{
    return base.SaveChangesAsync();
}

但是,除非您在 SaveChangesAsync 中有任何其他事情要做,否则这是毫无意义的(并且 Resharper 会为您将其变灰)。