我如何使用 Moq 来测试 returns 从数据库中列出的索引操作?
How can I use Moq to test my Index action that returns list from the database?
我正在学习为 ASP.NET MVC 5 使用单元测试和 Moq。我正在尝试为我的一个控制器的索引操作编写我的第一个单元测试。
这是索引操作的代码。
[Authorize]
public class ExpenseController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: /Expense/
public ActionResult Index()
{
return View(db.Expenses.ToList().Where(m => m.ApplicationUserId == User.Identity.GetUserId()));
}
}
我只想检查返回的视图是否为空
像这样
[TestMethod]
public void ExpenseIndex()
{
// Arrange
ExpenseController controller = new ExpenseController();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
当然,由于连接到数据库和使用ApplicationUserId
,这不起作用,所以你们能帮我对这个动作进行最小起订量和单元测试,或者给我推荐一个我可以的教程熟悉 ASP.NET MVC 中的模拟。
一种方法是抽象将依赖封装在虚方法中,例如:创建一个return用户开销的虚方法,现在你的控制器应该是这样的:
public class ExpenseController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: /Expense/
public ActionResult Index()
{
return View(GetUserExpenses());
}
protected virtual List<Expense> GetUserExpenses()
{
return db.Expenses.ToList().Where(m => m.ApplicationUserId == User.Identity.GetUserId());
}
}
然后,创建一个从您的控制器派生的存根 class,并覆盖 GetUserExpenses() 方法。它应该看起来像:
public class ExpenseControllerStub : ExpenseController
{
protected override List<Expense> GetUserExpenses()
{
return new List<Expense>();
}
}
现在在您的单元测试中,从 ExpenseControllerStub 而不是 ExpenseController 创建实例,它应该可以工作:
[TestMethod]
public void ExpenseIndex()
{
// Arrange
ExpenseControllerStub controller = new ExpenseControllerStub();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
这是手动操作的方法。如果您需要为此使用模拟框架,则需要使 GetUserExpenses() public 不受保护,然后设置 return 一个空的费用列表,例如:
var mock = new Moq.Mock<ExpenseController>();
mock.Setup(m => m.GetUserExpenses().Returns(new List<Expense>());
但我不喜欢用这种方法public!可能 Moq 有办法 configure/setup 保护方法,但我不知道。
编辑:一个更好的解决方案是完全抽象 Expenses 存储库,在这种情况下模拟它会很简单。
另一种解决方案是将 DbContext 注入控制器构造函数,并使用模拟框架来模拟它和 Expenses DbSet。您可以找到执行此操作的示例 here
编辑 #2:您也可以使用 TestStack.FluentMVCTesting or MvcContrib.TestHelper 来简化 MVC 测试。
我正在学习为 ASP.NET MVC 5 使用单元测试和 Moq。我正在尝试为我的一个控制器的索引操作编写我的第一个单元测试。
这是索引操作的代码。
[Authorize]
public class ExpenseController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: /Expense/
public ActionResult Index()
{
return View(db.Expenses.ToList().Where(m => m.ApplicationUserId == User.Identity.GetUserId()));
}
}
我只想检查返回的视图是否为空
像这样
[TestMethod]
public void ExpenseIndex()
{
// Arrange
ExpenseController controller = new ExpenseController();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
当然,由于连接到数据库和使用ApplicationUserId
,这不起作用,所以你们能帮我对这个动作进行最小起订量和单元测试,或者给我推荐一个我可以的教程熟悉 ASP.NET MVC 中的模拟。
一种方法是抽象将依赖封装在虚方法中,例如:创建一个return用户开销的虚方法,现在你的控制器应该是这样的:
public class ExpenseController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: /Expense/
public ActionResult Index()
{
return View(GetUserExpenses());
}
protected virtual List<Expense> GetUserExpenses()
{
return db.Expenses.ToList().Where(m => m.ApplicationUserId == User.Identity.GetUserId());
}
}
然后,创建一个从您的控制器派生的存根 class,并覆盖 GetUserExpenses() 方法。它应该看起来像:
public class ExpenseControllerStub : ExpenseController
{
protected override List<Expense> GetUserExpenses()
{
return new List<Expense>();
}
}
现在在您的单元测试中,从 ExpenseControllerStub 而不是 ExpenseController 创建实例,它应该可以工作:
[TestMethod]
public void ExpenseIndex()
{
// Arrange
ExpenseControllerStub controller = new ExpenseControllerStub();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
这是手动操作的方法。如果您需要为此使用模拟框架,则需要使 GetUserExpenses() public 不受保护,然后设置 return 一个空的费用列表,例如:
var mock = new Moq.Mock<ExpenseController>();
mock.Setup(m => m.GetUserExpenses().Returns(new List<Expense>());
但我不喜欢用这种方法public!可能 Moq 有办法 configure/setup 保护方法,但我不知道。
编辑:一个更好的解决方案是完全抽象 Expenses 存储库,在这种情况下模拟它会很简单。
另一种解决方案是将 DbContext 注入控制器构造函数,并使用模拟框架来模拟它和 Expenses DbSet。您可以找到执行此操作的示例 here
编辑 #2:您也可以使用 TestStack.FluentMVCTesting or MvcContrib.TestHelper 来简化 MVC 测试。