4

我有一种情况,在 MS Dynamics Crm 中,它使用密封类和只读属性返回一些对象(我只能假设使用内部构造函数或内部属性集)。而且这些人不会从我可以使用的界面继承。显然,如果我可以控制这段代码,我将拥有更多的控制权,但因为它位于底层的 MS Dynamics 框架中,所以我有点卡住了。

我想模拟/覆盖的类称为AliasedValue。我想模拟它的原因是我试图模拟对动态的调用并想假装我正在返回一些别名值。

所以这是场景,我想创建一个 Dynamics 将返回的示例实体......像这样:

var new_entity = new Entity("new_entity")
    {
        Attributes = new AttributeCollection
            {
                {"new_name", "BR"},
                {"createdon", DateTime.Now.AddDays(-1).Date},
                {"new_field", "My field"},
                {"new_contact", new AliasedValue {*****} }
            }
    };

所以我引用了一个“联系人”实体(实时返回为 AliasedValue)。在测试时,我想确保我的代码处理可能会在该字段中返回的某些值(例如,它知道如何处理别名值,并且如果没有返回链接的联系人,它就不会爆炸,等等)。

因此,如果您单击 AliasedValue 的链接,您会注意到属性是只读的……所以我无法设置测试数据……

接下来,我要创建自己的类并覆盖整个东西......但它是密封的......

最重要的是,正如您可能已经猜到的那样,Moq 不喜欢尝试模拟密封类。

我读过我需要购买一些“更好”的模拟框架来做到这一点,但我真的不想为了解决这件事而花一些额外的钱。

任何人都为我提供了一个很好的小解决方案来解决这个问题?

更新澄清


如何返回的示例如下。我有一项服务将被模拟以返回上述对象。或者它实际返回的是一个包含上述对象的集合。所以这就像这样:

var service = new Mock<IOrganizationService>();
service
    .Setup(s => s.RetrieveMultiple(null))
    .Returns(new EntityCollection (new List<Entity> {new_entity}));

太好了,我可以返回上面的实体并用它做我想做的事。因此,在我创建了上述实体并通过我的模拟服务返回它之后,我在我的“EntityCollection”中得到了上述内容。一旦我有了我的实体,我就可以按如下方式访问该属性:

var aliasedContact = (AliasedValue)new_entity.Attributes["new_contact"];

也许我很傻,但我不太明白答案(由 Lunivore 提供)将如何解决这个问题......(添加评论以获得反馈......)

4

2 回答 2

6

通过添加一个非常简单的适配器类从第三方库中抽象出来,您可以通过检查对其进行测试。与其扩展你的目标类,不如在它之上编写你的新类。它可以具有相同的方法名称、相同的属性等(尽管不是必须的)——它只是委托给密封类。

如果您有一个返回密封类的类,请将它们都包装起来。所以它可能看起来像这样:

var crmWrapper = new MSDynamicsCrmWrapper(_myMsDynamicsCrm);
var entityWrapper = crmWrapper.AliasedValue(url);

crmWrapper 将执行以下操作:

public EntityWrapper AliasedValue(Url url) 
{
    var entity = delegateCrm.AliasedValue(url);
    return new EntityWrapper(entity);
}

简单的。您只需要委托您实际使用的那些方法。

这不仅可以让您模拟该类,还可以让您控制,例如,下一个版本的 MS Dynamics 是否会稍微更改 API,或者出现奇怪的行为或性能不佳。此外,您正在将 API 范围缩小到您实际使用的部分,因此代码甚至可能更易于维护。

计算中没有什么是另一层抽象无法解决的……

于 2012-08-10T16:35:00.043 回答
0

为了模拟密封类,非虚拟方法或静态成员通常需要一个基于分析器的模拟框架,以便能够拦截所有调用。我所知道的唯一可以做到这一点并且它不是商业的框架是Microsoft Moles

对于 Visual Studio 2012,Moles 已重命名为 Fakes,并将包含在安装中。对于 Visual Studio 2010,您需要单独下载。由于它是一个基于探查器的框架,您需要使用他们的运行器运行您的测试,moles.runner.exe以便它可以设置探查器。

不久前,我写了一篇博客文章,描述了在 Moles 下运行 NUnit 测试的过程,您可以在以下位置查看:

使用 NUnit 和 Moles Redux 进行单元测试

另一种选择是遵循 Lunivore 答案的指示并添加一个抽象层。我自己更喜欢用工具来解决这个问题,但我必须提前告诉你,Moles 并不是那么容易使用。其他基于分析器的模拟框架,如TypeMock IsolatorJustMock可能更容易使用,但它们是商业解决方案。

于 2012-08-10T16:31:12.800 回答