说我们有
public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{ }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
public List<Post> Posts { get; set; }
}
public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
我想在单元测试中为Blog
和Post
提供数据。但博客包含帖子和帖子包含博客。
[编辑]
我想将DbContext
传递给控制器。因此,我必须模拟DbContext
和DbSet
。对于DbSet
,我需要播种一些虚拟数据。
例如:
在asp.net mvc控制器
public IActionResult GetBlog(int id)
{
Blog blog = _context.Blog.FirstOrDefault(x => x.BlogId == id);
return View(Blog);
}
在测试中
[Fact]
public void Get_blog_1_returns_google()
{
// Act
var result = _controller.GetBlog(1) as ViewResult;
// Assert
Assert.IsType(typeof(Blog), result.ViewData.Model);
Blog model = (Blog)result.ViewData.Model;
Assert.Equal("google", model.Url);
}
但我必须首先为测试提供数据。
public class BlogControllerTest
{
private BloggingContext _context;
private BlogController _controller;
public BlogControllerTest()
{
// Seed data
_context.Blog.Add(new Blog()
{
BlogId = 1,
Url = "google",
// how about Post
});
//..other code...
}
//...other code removed for brevity
}
如何模拟它们?
答案 0 :(得分:1)
首先,您应该创建一些抽象,以使DbContext
更容易模拟/测试
public interface IDbContext : IDisposable {
int SaveChanges();
}
public interface IBloggingContext : IDbContext {
DbSet<Blog> Blogs { get; }
DbSet<Post> Posts { get; }
}
通过这些抽象,您可以实现具体的BloggingContext
。
public class BloggingContext : DbContext, IBloggingContext {
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options) { }
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
假设您的BlogController
正在使用构造函数注入...
public class BlogController : Controller {
private IBloggingContext _context;
public BlogController(IBloggingContext bloggingContext) {
this._context = bloggingContext;
}
public IActionResult GetBlog(int id) {
Blog blog = _context.Blogs.FirstOrDefault(x => x.BlogId == id);
return View(blog);
}
}
您现在可以使用像 Moq 这样的模拟框架来模拟IBloggingContext
以返回Blog
和Post
的虚假/模拟实例。
public class BlogControllerTest {
private IBloggingContext _context;
private BlogController _controller;
public BlogControllerTest() {
//creating seed objects
var post = new Post() {
PostId = 1,
Title = "Some title",
Content = "post contemt"
};
var blog = new Blog() {
BlogId = 1,
Url = "google",
Posts = new List<Post>() { post }
};
//associating blog with post
post.Blog = blog;
post.BlogId = blog.BlogId;
var blogsMock = new List<Blog>() { blog }.AsDbSetMock();
var postsMock = new List<Post>() { post }.AsDbSetMock();
var contextMock = new Mock<IBloggingContext>();
contextMock.Setup(m => m.Blogs).Returns(blogsMock.Object);
contextMock.Setup(m => m.Posts).Returns(postsMock.Object);
_context = contextMock.Object;
_controller = new BlogController(_context);
}
[Fact]
public void Get_blog_1_returns_google() {
// Act
var result = _controller.GetBlog(1) as ViewResult;
// Assert
Assert.IsType(typeof(Blog), result.ViewData.Model);
Blog model = (Blog)result.ViewData.Model;
Assert.Equal("google", model.Url);
}
}