我是Moq的新手,我想用它来编写单元测试。我有一个包含几个表的数据库,例如:
EducationUser | Application
- UsrName - Student
- UsrPwd - CourseId
- UsrChallenge - Date
- IsTeacher - Grade
- FullName
这是localdb
上的数据库,我想模拟它。我使用实体框架创建了实体。这些实体的接口是IEducationEntities
。
现在我想创建一个模拟对象并对某些Web服务进行一些测试,例如:
[TestMethod()]
public void LoginTest()
{
HttpResponseMessage response = Request.CreateResponse(_accountController.Login("andrew", "DefaultPassword"));
Assert.IsTrue(response.IsSuccessStatusCode, "User unable to log in with correct login info");
}
为此,根据我对documentation的理解,我应该可以做类似的事情:
[TestClass()]
public class AccountControllerTests : ApiController
{
Mock<IEducationEntities> _entities = new Mock<IEducationEntities>(MockBehavior.Strict);
private AccountController _accountController;
public AccountControllerTests() {
_accountController = new AccountController(_entities.Object);
_entities.Setup(table => table.EducationUsers.UsrName).Returns("andrew");
_entities.Setup(table => table.EducationUsers.UsrPwd).Returns("DefaultPassword");
}
[TestMethod] //etc, defining tests below
然而,这根本不起作用,因为从数据库生成的实体显然不包含有关子字段的信息,我收到错误:
'DbSet'不包含'UsrPwd'的定义 没有扩展方法'UsrPwd'接受类型的第一个参数 可以找到'DbSet'(你是否错过了使用 指令或程序集引用?)
我错过了什么?如何使用与我的数据库具有相同结构的测试数据填充moq
对象?
答案 0 :(得分:2)
This article describes how to mock your Entity Framework context(假设您使用的是版本6或更高版本)
你会做这样的事情:
[TestMethod]
public void TestSomething()
{
// Create the user data
var educationUsers = new List<EducationUser>
{
new EducationUser
{
UsrName = "andrew",
UsrPwd = "DefaultPassword"
}
}.AsQueryable();
// Create the DbSet that contains the user data and wire it up to return the user data that was created above
Mock<DbSet<EducationUser>> educationUsersDbSet = new Mock<DbSet<EducationUser>>();
educationUsersDbSet.As<IQueryable<EducationUser>>().Setup(m => m.Provider).Returns(educationUsers.Provider);
educationUsersDbSet.As<IQueryable<EducationUser>>().Setup(m => m.Expression).Returns(educationUsers.Expression);
educationUsersDbSet.As<IQueryable<EducationUser>>().Setup(m => m.ElementType).Returns(educationUsers.ElementType);
educationUsersDbSet.As<IQueryable<EducationUser>>().Setup(m => m.GetEnumerator()).Returns(educationUsers.GetEnumerator());
// Create the mock context and wire up its EducationUsers property to return the DbSet that was created above
var context = new Mock<IEducationEntities>();
context.Setup(e => e.EducationUsers).Returns(educationUsersDbSet.Object);
// Create the account controller using the mock DbContext
_accountController = new AccountController(context.Object);
// ... the rest of your testing code ...
}
为所有单元测试的每个实体类型配置模拟DbSet
可能会很烦人,因此您可以创建一个方法来完成它。
public static Mock<DbSet<TEntity>> CreateMockDbSet<TEntity>(IQueryable<TEntity> models) where TEntity : class
{
Mock<DbSet<TEntity>> dbSet = new Mock<DbSet<TEntity>>();
dbSet.As<IQueryable<TEntity>>().Setup(e => e.ElementType).Returns(models.ElementType);
dbSet.As<IQueryable<TEntity>>().Setup(e => e.Expression).Returns(models.Expression);
dbSet.As<IQueryable<TEntity>>().Setup(e => e.GetEnumerator()).Returns(models.GetEnumerator());
dbSet.As<IQueryable<TEntity>>().Setup(e => e.Provider).Returns(models.Provider);
return dbSet;
}
然后您的测试方法变为
[TestMethod]
public void TestSomething()
{
// Create the user data
var educationUsers = new List<EducationUser>
{
new EducationUser
{
UsrName = "andrew",
UsrPwd = "DefaultPassword"
}
}.AsQueryable();
// Create the DbSet that contains the user data and wire it up to return the user data that was created above
Mock<DbSet<EducationUser>> educationUsersDbSet = new CreateMockDbSet(educationUsers);
// Create the mock context and wire up its EducationUsers property to return the DbSet that was created above
var context = new Mock<IEducationEntities>();
context.Setup(e => e.EducationUsers).Returns(educationUsersDbSet.Object);
// Create the account controller using the mock DbContext
_accountController = new AccountController(context.Object);
// ... the rest of your testing code ...
}