Entity framework 使用ASP.net核心MVC应用程序中的列表为View()创建单元测试
我是单元测试新手。我有一个控制器-Entity framework 使用ASP.net核心MVC应用程序中的列表为View()创建单元测试,entity-framework,unit-testing,asp.net-core,asp.net-core-mvc,moq,Entity Framework,Unit Testing,Asp.net Core,Asp.net Core Mvc,Moq,我是单元测试新手。我有一个控制器-studentscoontroller和依赖注入,还有我的Index()方法: public class StudentsController : Controller { public readonly UniversityContext _context;//Database public StudentsController(UniversityContext context) { _context = contex
studentscoontroller
和依赖注入,还有我的Index()
方法:
public class StudentsController : Controller
{
public readonly UniversityContext _context;//Database
public StudentsController(UniversityContext context)
{
_context = context;
}//Constructor with database
// GET: Students
public async Task<IActionResult> Index()
{
return View(await _context.Students.ToListAsync());
}
}
公共类学生控制器:控制器
{
公共只读大学上下文_context;//数据库
公立学生控制员(大学上下文)
{
_上下文=上下文;
}//带数据库的构造函数
//获得:学生
公共异步任务索引()
{
返回视图(wait_context.Students.toListSync());
}
}
接下来,我需要编写一个正确的单元测试代码,如果:
1) 视图()与我的学生有一个列表
2) 对学生的查询不为空
我读过关于模拟对象的书,但我不知道如何编写正确的代码。到目前为止我编写的代码:
public class StudentsControllerTests
{
[Fact]
public async Task Index_ReturnsAViewResult_WithAListOfStudents()
{
var mockRepo = new Mock<UniversityContext>();
mockRepo.Setup(repo => repo.Students.ToList()).Returns(GetTestStudents());//There i get following error:Expression references a method that does not belong to the mocked object
var controller = new StudentsController(mockRepo.Object);
// Act
var result = controller.Index();
//// Assert
var viewResult = Assert.IsType<ViewResult>(result);
var model = Assert.IsAssignableFrom<IEnumerable<Student>>(
viewResult.ViewData.Model);
Assert.NotNull(model);//Second Condition
}
public List<Student> GetTestStudents()
{
var sessions = new List<Student>();
sessions.Add(new Student()
{
bDate = new DateTime(1994, 7, 2),
Name = "Test One"
});
sessions.Add(new Student()
{
bDate = new DateTime(1995, 7, 1),
Name = "Test Two"
});
return sessions;
}
}
公共类学生控件测试
{
[事实]
公共异步任务索引_ReturnsAViewResult_with alistofstudents()
{
var mockRepo=new Mock();
mockRepo.Setup(repo=>repo.Students.ToList()).Returns(GetTestStudents());//在这里我得到了以下错误:表达式引用了不属于模拟对象的方法
var controller=newstudentscocontroller(mockRepo.Object);
//表演
var result=controller.Index();
////断言
var viewResult=Assert.IsType(结果);
var model=Assert.IsAssignableFrom(
viewResult.ViewData.Model);
Assert.NotNull(model);//第二个条件
}
公共列表GetTestStudents()
{
var sessions=新列表();
sessions.Add(新学生()
{
b日期=新的日期时间(1994,7,2),
Name=“测试一”
});
sessions.Add(新学生()
{
b日期=新的日期时间(1995,7,1),
Name=“测试二”
});
返回会议;
}
}
有人能给我解释一下,如何更正我的代码吗?您只需要模拟上下文的成员,在本例中是
.Students
属性ToList
是对属性调用的扩展方法,不能被moq模拟
另外,.Students
是一个DbSet,也需要被模仿
使用此答案中的测试类:
派生了以下通用扩展方法
public static class MockDbSetExtensions {
public static Mock<DbSet<T>> AsDbSetMock<T>(this IEnumerable<T> list) where T : class {
IQueryable<T> queryableList = list.AsQueryable();
Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider);
dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression);
dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType);
dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator());
return dbSetMock;
}
public static Mock<DbSet<T>> ToAsyncDbSetMock<T>(this IEnumerable<T> source)
where T : class {
var data = source.AsQueryable();
var mockSet = new Mock<DbSet<T>>();
mockSet.As<IAsyncEnumerable<T>>()
.Setup(m => m.GetEnumerator())
.Returns(new TestAsyncEnumerator<T>(data.GetEnumerator()));
mockSet.As<IQueryable<T>>()
.Setup(m => m.Provider)
.Returns(new TestAsyncQueryProvider<T>(data.Provider));
mockSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => data.GetEnumerator());
return mockSet;
}
}
到
有一个问题。“无法从列表转换为Microsoft.EntityFrameworkCore.DbSet”@Eldar您是对的,我犯了一个错误。更新答案now@Eldar那
ToListAsync
也会给你带来一些麻烦。现在我得到了以下错误:非虚拟(在VB中可重写)成员上的设置无效:repo=>repo。Students@Eldar检查DbContext并确保Students属性是虚拟的
mockRepo.Setup(repo => repo.Students.ToList()).Returns(GetTestStudents());
var studentsMockedDbSet = GetTestStudents().ToAsyncDbSetMock();
mockRepo.Setup(repo => repo.Students).Returns(studentsMockedDbSet.Object);