设置Mocked ViewModel进行单元测试

时间:2016-03-01 15:07:33

标签: c# unit-testing tdd

以下是该方案:

我正在为我的控制器编写测试,需要设置一个标题为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"];
}

3 个答案:

答案 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 成为公共属性。然后,在测试中,您将会话设置为您在测试中创建的实例。