【问题标题】:How to mock viewmodel which is not a parameter of the action?如何模拟不是动作参数的视图模型?
【发布时间】:2014-06-06 18:10:17
【问题描述】:

以下是我的操作代码:-

   public ActionResult Edit(int id)
   {        
       ProductViewModel viewmodel = GetProduct(id);

       if (viewmodel != null)
       {
               ....................
       }
    }

在上面的代码中,if 条件基于 viewmodel。它从 GetProduct() 方法返回。其中 GetProduct() 方法是控制器的私有方法。

我想用 MOQ 在我的单元测试方法中模拟 ProductViewModel。谁能建议我最好的方法是什么?

【问题讨论】:

  • 视图模型通常只是一个数据容器。因此,您应该模拟 GetProduct() 方法并让它只返回一些静态数据(或 null,因为您需要对其进行测试)
  • ViewModels 通常是为视图而设计的数据结构......模拟它的价值是什么?
  • @Tommy,GetProduct() 是控制器的私有方法,我不是在模拟私有方法。为了测试视图模型条件中的内容,我想模拟视图模型。
  • 我会提出您的应用程序结构错误的论点。 GetProduct 是一种业务逻辑方法,不应该是私有的,应该在业务逻辑层/类中。这就是为什么你在努力完成你想要做的测试。按照您现在的结构方式,没有将任何值注入该控制器的入口点。为此,您需要研究依赖注入/控制反转类型的编程方法。
  • @Tommy,也许你是对的,但它是我的应用程序的旧结构,目前我无法修改它。但是有什么方法可以模拟视图模型并测试我的进一步行动?

标签: c# unit-testing asp.net-mvc-4 moq viewmodel


【解决方案1】:

理想情况下,您的 viewModel 应该只具有您的视图将绑定到的公共属性。因此,不应该存在需要模拟 viewModel 类的情况。 如果可能,模拟 GetProduct 方法以返回已设置公共属性的 ProductViewModel 实例。这样,您的 viewModel 将准确返回您希望它为您的测试用例返回的值。

【讨论】:

    【解决方案2】:

    通常使用 MVVM 模式将如下所示:

    public class MainViewModel : MyViewModelBase
    {
        private readonly IDataService _dataService;
    
        public MainViewModel(IDataService dataService)
        {
            _dataService = dataService;
            // ...
        }
        //..
    }  
    

    您将拥有一个如下所示的定位器:

    public class ViewModelLocator
    {
        static ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
    
            if (ViewModelBase.IsInDesignModeStatic)
            {
                SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
            }
            else
            {
                SimpleIoc.Default.Register<IDataService, DataService>();
            }
    
            // Here you'll register your view models
            SimpleIoc.Default.Register<MainViewModel>();
        }  
        //..
    }
    

    因此,模拟这个相当容易,只需使用 DI 传递您想要传递的任何内容,并将您的方法挂钩到静态数据(通常这样做是为了在设计模式下获得良好的输出)或将返回的虚拟方法无论你需要什么。

    【讨论】:

      【解决方案3】:

      正确的方法是间接测试 GetProduct 方法。根据您从某种存储中获取信息的名称,您可以模拟该存储并返回一个对象,该对象由您想要的 ViewModel 中的 GetProduct 映射。您不应该模拟您正在测试的同一类的方法。

      【讨论】:

        【解决方案4】:

        您的控制器与业务逻辑紧密耦合,在本例中为 GetProduct 方法。我建议重组您的代码,以便为您的“产品”特定业务逻辑提供接口。产品控制器应该依赖于抽象,即接口,而不是任何具体的东西。

        使用任何依赖注入框架,如 sring.net、MS unity 等,将具体实现(依赖)注入您的控制器。

        现在使用 MOQ 模拟业务逻辑,以便可以单独测试控制器。

        最后,这只是另一个很好的例子,它展示了如果对特定代码组件进行单元测试变得困难,它往往指向设计缺陷,而不是单元测试/模拟框架的无能。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-02-26
          • 1970-01-01
          • 1970-01-01
          • 2011-03-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-20
          相关资源
          最近更新 更多