我第一次尝试.NET核心,并看到如何在单元测试中使用Moq。开箱即用,在创建控制器,其中ApplicationDbContext是参数的构造函数是这样的:我如何在.NET核心Moq ApplicationDbContext
public class MoviesController : Controller
{
private readonly ApplicationDbContext _context;
public MoviesController(ApplicationDbContext context)
{
_context = context;
}
这里的单元测试,我开始测试控制器时:
[TestClass]
public class MvcMoviesControllerTests
{
[TestMethod]
public async Task MoviesControllerIndex()
{
var mockContext = new Mock<ApplicationDbContext>();
var controller = new MoviesController(mockContext.Object);
// Act
var result = await controller.Index();
// Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
}
但随后我意识到ApplicationDbContext是一个具体的类,它没有无参数的构造函数,所以测试不起作用。它给了我错误:无法找到无参数的构造函数。
也许这可能是一个更多针对Moq的问题,而不是它与.NET Core相关,但我也是Moq的新手,所以我不知道如何继续。下面是当我创建项目ApplicationDbContext代码是如何产生的:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
public DbSet<Movie> Movie { get; set; }
}
需要什么改变让我的单元测试会成功吗?
UPDATE:
我从https://msdn.microsoft.com/en-us/magazine/mt703433.aspx发现,您可以配置EF核心使用内存数据库进行单元测试。所以我改变我的单元测试看起来像这样:
[TestMethod]
public async Task MoviesControllerIndex()
{
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseInMemoryDatabase();
var _dbContext = new ApplicationDbContext(optionsBuilder.Options);
var controller = new MoviesController(_dbContext);
// Act
var result = await controller.Index();
// Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
}
这个测试现在成功了。但是,这是做这件事的正确方法吗?显然,我完全消除了用Moq嘲笑ApplicationDbContext!还是有另一种解决方案来解决这个问题使用Moq。
即使使用内存中的DbContext,您也基本上正在进行集成测试,这仍然是必需的。然而,从设计的角度来看,你应该让你的课程取决于抽象而不是结核。创建一个接口,公开您需要的功能并让您的具体上下文继承于此。 – Nkosi
我同意@Nkosi这是现在有效的集成测试。当ApplicationDbContext实现'IdentityDbContext'时,你可能可以将接口注入到你的控制器中,然后模拟它吗? –
Corporalis