简体   繁体   English

设置模拟ViewModel以进行单元测试

[英]Setup Mocked ViewModel for Unit Testing

Here is the scenario: 这是场景:

I'm writing a test for my controller and need to setup a view model titled CheckoutViewModel . 我正在为控制器编写测试,并且需要设置一个名为CheckoutViewModel的视图模型。 My controller method, Products does not take CheckoutViewModel as a parameter, so I cannot pass it in that way. 我的控制器方法Products不将CheckoutViewModel作为参数,因此无法以这种方式传递它。

Currently, the test fails returning a Null Exception because CheckoutViewModel is not getting set and called. 当前,由于未设置和调用CheckoutViewModel ,因此测试无法返回Null Exception

Question: How can I setup my CheckoutViewModel with data. 问题:如何使用数据设置CheckoutViewModel

Error Details: 错误详情:

  • System.NullReferenceException System.NullReferenceException

  • Object reference not set to an instance of an object 你调用的对象是空的

Current Test 当前测试

[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));
}

Controller 控制者

 [AccectReadVerbs]
 public ActionResult Products()
 {
    CheckoutViewModel checkoutViewModel = GetCheckoutViewModel();
    var checkoutId = checkoutViewModel.CheckoutId;
    var result = _productOrchestrator.Products(checkoutId, currentSession)

    return View(result);
 }

Failing on this method 无法使用此方法

private CheckoutViewModel GetCheckoutViewModel()
{
    if(Session["CheckoutViewModel"] == null)
    {
        return new CheckoutViewModel();
    }
    return (CheckoutViewModel)Session["CheckoutViewModel"];
}

If GetCheckoutViewModel has some dependencies on ie services, dbConnection or other complex classes, you need to add a class with an interface, move the method for GetCheckOutViewModel to the class and take the new interface as a dependency to the controller. 如果GetCheckoutViewModel对服务,dbConnection或其他复杂类具有某些依赖关系,则需要添加具有接口的类,将GetCheckOutViewModel的方法移至该类,然后将新接口作为对控制器的依赖关系。 Then you need to mock the new interface. 然后,您需要模拟新界面。

Or edit your viewmodel to take interface dependencies on the stuff that stands in the way of unit testing, ie the Session. 或编辑您的视图模型以获取依赖于单元测试(即会话)的接口的接口依赖性。

I think you could create some interface: 我认为您可以创建一些接口:

public interface ISessionManager { Session session {get; set;} }

Then your controller constructor: 然后是您的控制器构造函数:

public ProductsController(ISessionManager sm) { _sessionManager = sm; }

Then you can pass a mocked instance to your controller. 然后,您可以将模拟实例传递给控制器​​。

I'm guessing that the exceptions is due to the fact that when you're running the unit test there will not be any (webserver) session available. 我猜这是由于以下事实造成的:当您运行单元测试时,将没有任何可用的(网络服务器) 会话 What you want do is to isolate your tests from any external dependencies - and a session state that is part of the webserver hosting environment would be an external dependency. 您要做的就是将测试与任何外部依赖关系隔离开-并且作为Web服务器托管环境一部分的会话状态将是一个外部依赖关系。

To solve this you need to either mock or stub out the Session object from your test. 为了解决这个问题,您需要从测试中模拟或存根Session对象。 There are many ways to do this, but the easiest way would be to make Session a public property on the Controller. 有许多方法可以做到这一点,但最简单的方法是将Session设为Controller上的公共属性。 From your test you would then set the Session to an instance you create within your test. 然后从测试中将会话设置为在测试中创建的实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM