以下是该方案:
我正在为我的控制器编写测试,需要设置一个标题为CheckoutViewModel
的视图模型。我的控制器方法Products
不会将CheckoutViewModel
作为参数,因此我无法以这种方式传递它。
目前,测试无法返回Null Exception
,因为CheckoutViewModel
未设置并被调用。
问题:如何使用数据设置
CheckoutViewModel
。
错误详细信息:
System.NullReferenceException
对象引用未设置为对象的实例
当前测试
[TestMethod]
public void Products_ProductControllerIsCalled_ReturnsViewWithProducts()
{
// Arrange
var currentSession = _autoMoqer.GetMock<ICurrentSession>().Object;
ProductController productController = new ProductController(currentSession);
var checkoutViewModel = new CheckoutViewModel
{
CheckoutId = new Guid()
};
// Act
ActionResult result = productController.Products();
// Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
}
控制器
[AccectReadVerbs]
public ActionResult Products()
{
CheckoutViewModel checkoutViewModel = GetCheckoutViewModel();
var checkoutId = checkoutViewModel.CheckoutId;
var result = _productOrchestrator.Products(checkoutId, currentSession)
return View(result);
}
此方法失败
private CheckoutViewModel GetCheckoutViewModel()
{
if(Session["CheckoutViewModel"] == null)
{
return new CheckoutViewModel();
}
return (CheckoutViewModel)Session["CheckoutViewModel"];
}
答案 0 :(得分:0)
如果GetCheckoutViewModel对某些服务,dbConnection或其他复杂类有依赖关系,则需要添加一个带接口的类,将GetCheckOutViewModel的方法移动到该类,并将新接口作为控制器的依赖项。然后你需要模拟新界面。
或者编辑你的viewmodel以接受与单元测试相关的东西的接口依赖性,即Session。
答案 1 :(得分:0)
我认为你可以创建一些界面:
public interface ISessionManager
{
Session session {get; set;}
}
然后你的控制器构造函数:
public ProductsController(ISessionManager sm)
{
_sessionManager = sm;
}
然后您可以将模拟的实例传递给控制器。
答案 2 :(得分:0)
我猜测异常是由于当您运行单元测试时,不会有任何(网络服务器)会话可用。您想要做的是将测试与任何外部依赖关系隔离 - 并且作为Web服务器托管环境一部分的会话状态将是外部依赖关系。
要解决此问题,您需要在测试中模拟或删除 Session 对象。有很多方法可以做到这一点,但最简单的方法是在Controller上使 Session 成为公共属性。然后,在测试中,您将会话设置为您在测试中创建的实例。