我是第一次尝试使用.NET Core,看看Moq如何用于单元测试.开箱即用,创建控制器,其中ApplicationDbContext是构造函数的参数,如下所示:
public class MoviesController : Controller
{
private readonly ApplicationDbContext _context;
public MoviesController(ApplicationDbContext context)
{
_context = context;
}
Run Code Online (Sandbox Code Playgroud)
这是我在测试控制器时开始的单元测试:
[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));
}
Run Code Online (Sandbox Code Playgroud)
但后来我意识到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; }
}
Run Code Online (Sandbox Code Playgroud)
我需要更改什么才能使我的单元测试成功?
更新:
我从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));
}
Run Code Online (Sandbox Code Playgroud)
此测试现在成功.但这是正确的做法吗?显然,我完全消除了用Moq模拟ApplicationDbContext!或者是否有使用Moq的此问题的另一种解决方案.
Tim*_*riv 20
模拟DbContext不起作用,因为需要太多的提供程序才能使其工作.更简单的解决方案是使用Microsoft为此目的实现的InMemory解决方案.请不要创建仅用于测试的仓库(仍然不测试EF代码).
以下是如何使用.net core中的InMemory数据库进行测试的链接
https://docs.efproject.net/en/latest/miscellaneous/testing.html
小智 5
如果有人感兴趣,我会了解@Corporalis的想法,并实现了一个接口以将ApplicationDbContext暴露给测试项目。
public interface IApplicationDbContext
{
DbSet<Movie> Movies { get; set; }
int SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)
并在ApplicationDbContext中
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>, IApplicationDbContext
{
public virtual DbSet<Movie> Movies { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
Run Code Online (Sandbox Code Playgroud)
不要忘记在StartUp.cs,ConfigureServices中注册接口
services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());
Run Code Online (Sandbox Code Playgroud)
因此,现在在Controller或Service或您必须使用ApplicationDbContext的每个方法中,改为对接口进行引用
public class filterMovies
{
private readonly IApplicationDbContext _context
public filterMovies(IApplicationDbContext context)
{
_context = context;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以随意使用接口来模拟ApplicationDbContext,而不是自己实现
var mockContext = new Mock<IApplicationDbContext>();
mockContext.Setup(mc => mc.Movies).Returns(mockDbSet.Object);
Run Code Online (Sandbox Code Playgroud)
希望对您有所帮助;)
只需 2 行:
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
var context = new Mock<ApplicationDbContext>(optionsBuilder.Options);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
14422 次 |
最近记录: |