在设计时代码中使用模拟框架的缺点

本文关键字:模拟 框架 缺点 时代 代码 | 更新日期: 2023-09-27 18:34:26

我正在为我的公司开发一个棱镜模板。 我想使设计时数据尽可能容易地使用。

为此,我正在创建一个继承自我 ViewModel 的设计类。 DesignViewModel 将调用我的 ViewModel 的构造函数。

我的 ViewModel 构造函数有时会调用棱镜方法和属性,如 IRegionManager.Regions 。 我正在考虑为将使用 NSubstitute 的接口制作一个存根。 喜欢这个:

public class DesginRegionManager : IRegionManager
{
    public IRegionManager CreateRegionManager(){return this;}
    private readonly IRegionCollection regions;
    public DesginRegionManager()
    {
        regions = Substitute.For<IRegionCollection>();   <--------
    }                                                            |
                                                                 |
    public IRegionCollection Regions {get { return regions; }}   |
}                                                                |
                                                                 |
// Using NSubstitute here ----------------------------------------

我打算为IUnityContainer做类似的事情.

除了单元测试之外,我从未在任何事情中使用过 Mocking 框架。 这样使用它是个坏主意吗?

虽然它永远不会在生产代码中调用,但它将为我的实际应用程序添加对 NSubstitute 的依赖。

这样做有缺点吗?

在设计时代码中使用模拟框架的缺点

在继续之前,我对 Prism 的经验很少,尽管我以前使用过 caliburn,所以我将假设它以类似的方式工作。但我确实有一点经验。

出于设计目的使用替代品是一个坏主意吗?

我的简短回答是否定的

并不完全理想,但是当您有一个设计部门(或在您继续编码时负责UI元素的人(将UI执行的代码与设计过程隔离开来是一种很好的做法,因为即使要实时执行的代码有问题,您也可以通过界面进行改进。

当我说替代品时,我指的是通过Visual Studio或blend在设计时创建的真实(示例数据(实例。(我将在最后提供一个示例(。

嘲笑这些元素是个坏主意吗?

也许不是,尽管您将在项目中包含更多依赖项,这些依赖项对于项目的执行并不那么重要。

积极的一面是:

模拟

定义意味着您将维护更少的代码,但您将无法模拟这些虚假实例上的数据(或者除非您开始为每个模拟返回示例数据,否则不会(。

消极的一面:

首先,根据模拟框架,您将加载(在设计时(动态创建的代理或假实例,以模拟拦截调用和其他内容的某些行为。如果您创建的大量对象不如实际代码轻量级,这可能是一个痛苦的操作。

除了你的设计师(如果有一个混合大师(将不得不收集地狱nsubstitute(或你喜欢的模拟框架(如何工作的知识。

如果我有一个设计器上限,并且您向我展示了一个具有特定定义的类,我可以复制该类,而不是使用称为 substitute 的外部库定义的类,我可能会告诉您我更喜欢第一个选项,因为我不需要学习任何其他东西除了一点 c#。即使这样,我也不会尝试触摸该代码。

在您的项目中添加 nreplace 有什么缺点吗?

只要您正确使用 DesignInstance,并且带有模拟的代码引用与实际功能隔离,并且您不尝试替换非虚拟属性,或具有多个参数或密封类的实例(基本上对替换内容的任何限制(,您就会没问题,因为设计属性将在代码的特殊模式下执行。

特别是 NSubstitute 可能会在尝试创建实例或访问某些属性时引发异常,在这种情况下,IDE 可能会在加载实例时崩溃或使控件崩溃。

有样品吗?

你可能知道该写什么,但它就在这里(虽然不是棱镜(。

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/winfx/expression/blend/2008"
    xmlns:vm="clr-namespace:Project.Namespace.ViewModels.DataSamples"
    d:DataContext="{d:DesignInstance IsDesignTimeCreatable=True, Type={x:Type NationViewModelSampleData}}">
    <StackPanel DataContext="{Binding Leader}">
        <TextBlock Text="{Binding FirstName}" />
        <TextBlock Text="{Binding LastName}" />
    </StackPanel>
</UserControl>

NationViewModel实现了这样的接口

namespace Project.Namespace.ViewModels
{
    public interface INationViewModel
    {
        IPerson Leader { get; }
        IEnumerable<IPerson> Citizens { get; }
    }
    public interface IPerson
    {
        string FirstName { get; }
        string LastName { get; }
    }
}

示例数据为:

namespace Project.Namespace.ViewModels.DataSamples
{
    public class NationViewModelSampleData : Project.Namespace.ViewModels.INationViewModel
    {
        public NationViewModelSampleData()
        {
            // You could have done something like this as well, but for this sample was more code to write.
            // Leader = Substitute.For<IPerson>();
            // Leader.FirstName.Returns("John");
            // Leader.LastName.Returns("Doe");
            // or just...
            Leader = new Person { FirstName = "John", LastName = "Doe" };
            Citizens = new IPerson[]
                       {
                           new Person { FirstName = "Malcolm", LastName = "Little" },
                           Leader
                       };
            // You could have applied the mock to this section as well... again, more code for this scenario than just a simple real instance.
        }
        public IPerson Leader { get; private set; }
        public IEnumerable<IPerson> Citizens { get; private set; } 
    }
}

在这个示例中,我决定使用实际实例,因为我想象中的 Person 实现非常小且使用安全......但我希望它的复杂性会增加,我可能也想减少这种松弛,只实现我的 PersonSampleData 实例或像您之前描述的那样模拟它。

希望此评论对您有所帮助。

干杯!