【发布时间】:2021-07-11 19:09:15
【问题描述】:
我是第一次尝试 .NET Core,看看如何在单元测试中使用 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; }
}
我需要进行哪些更改才能使我的单元测试成功?
更新:
我从https://msdn.microsoft.com/en-us/magazine/mt703433.aspx 发现,您可以配置 EF Core 以使用内存数据库进行单元测试。所以我改变了我的单元测试看起来像这样:
[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 这现在实际上是一个集成测试。当然
ApplicationDbContext实现了`IdentityDbContext`,你可以将接口注入你的控制器然后模拟它吗?
标签: asp.net-core moq