使用 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 会为您将其变灰)。
我目前正在为我的 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 会为您将其变灰)。