Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在设计时代码中使用模拟框架的缺点_C#_.net_Wpf_Mocking_Nsubstitute - Fatal编程技术网

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

C# 在设计时代码中使用模拟框架的缺点,c#,.net,wpf,mocking,nsubstitute,C#,.net,Wpf,Mocking,Nsubstitute,我正在为我的公司制作棱镜模板。我想使设计时数据尽可能容易处理 为此,我将创建一个继承自ViewModel的设计类。DesignViewModel将调用我的ViewModel的构造函数 我的ViewModel构造函数有时会调用prism方法和属性,如IRegionManager.Regions。我正在考虑为将使用NSubstitute的接口制作一个存根。像这样: public class DesginRegionManager : IRegionManager { public IRegi

我正在为我的公司制作棱镜模板。我想使设计时数据尽可能容易处理

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

我的ViewModel构造函数有时会调用prism方法和属性,如
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 ----------------------------------------
公共类DesginRegionManager:IRegionManager
{
公共IRegionManager CreateRegionManager(){返回此;}
专用只读区域收集区域;
公共设计区域管理器()
{

regions=Substitute.For();在继续之前,我对Prism几乎没有经验,尽管我以前曾与caliburn合作过,所以我假设它以类似的方式工作。但我对nsubstitute确实有一点经验

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

我的简短回答是否定的

这并不完全理想,但当您有一个设计部门(或在您继续编码时负责UI元素的人)时,将UI执行的代码与设计过程隔离是一种很好的做法,因为即使实时执行的代码有缺陷,您也能够在界面上进行改进

当我说替换时,我指的是在设计时由VisualStudio或blend创建的真实(如示例数据)实例(最后我将提供一个示例)

模仿这些元素是个坏主意吗?

也许不会,尽管您将为您的项目添加更多的依赖项,而这些依赖项对于项目的执行来说并不是那么重要

积极的一面是:

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

这方面的负面影响是:

首先,根据模拟框架的不同,您将(在设计时)加载动态创建的代理或伪造的实例,以模拟拦截调用和其他内容的某些行为。如果您创建的对象数量越来越多,但没有真正的代码那么轻,这可能是一个痛苦的操作

除此之外,你的设计师(如果有一位混合大师的话)还必须收集关于nsubstitute(或者你喜欢的模拟框架)是如何工作的知识

如果我有一个设计器cap,你给我看一个具有特定定义的类,我可以复制这个类,而不是使用一个名为replacement的外部库定义的类,我可能会告诉你,我更喜欢第一个选项,因为除了一点c#之外,我不需要学习其他任何东西。即使这样,我也不会尝试去接触这些代码

将nsubstitute添加到项目中有什么缺点吗?

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

NSSubstitute尤其可能会在尝试创建实例或访问某些属性时引发异常,在这种情况下,IDE可能会在加载时崩溃或崩溃控件

有样品吗?

你可能知道该写什么,但现在开始了(不是棱柱体)


其中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
{
公共接口视图模型
{
IPerson前导{get;}
IEnumerable公民{get;}
}
公共接口IPerson
{
字符串名{get;}
字符串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; } 
    }
}
namespace Project.namespace.ViewModels.DataSamples
{
公共类NationViewModelSampleData:Project.Namespace.ViewModels.INationViewModel
{
public NationViewModelSampleData()
{
//您也可以这样做,但是对于这个示例,需要编写更多的代码。
//Leader=替换为();
//Leader.FirstName.Returns(“约翰”);
//Leader.LastName.Returns(“Doe”);
//或者只是。。。
领导=新人{FirstName=“John”,LastName=“Doe”};
公民=新IPerson[]
{
新人{FirstName=“Malcolm”,LastName=“Little”},
领导
};
//您也可以将mock应用到这一部分……同样,这个场景的代码比一个简单的真实实例还要多。
}
公共IPerson前导{get;私有集;}
公共IEnumerable公民{get;private set;}
}
}
在这个示例中,我决定使用实际的实例,因为我想象中的Person实现非常小,使用起来也很安全……但我希望它会变得越来越复杂,我可能也想减少这一点,只实现PersonSampleData实例,或者像您前面描述的那样模拟它

希望此评论对您有所帮助


干杯!

回答得很好!!谢谢你为我列出了利弊。
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; } 
    }
}